<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Pramit Marattha]]></title><description><![CDATA[Technical Content Lead]]></description><link>https://pramitmarattha.com.np</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1671130972537/RoN5Ff7rn.png</url><title>Pramit Marattha</title><link>https://pramitmarattha.com.np</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 14 Oct 2026 23:28:21 GMT</lastBuildDate><atom:link href="https://pramitmarattha.com.np/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[22 Best DataOps Tools To Optimize Your Data Management and Observability In 2023]]></title><description><![CDATA[The data landscape is rapidly evolving, and the amount of data being produced and distributed on a daily basis is downright staggering. According to the report by Statista, currently, there are approximately 120 zettabytes of data in existence (as of...]]></description><link>https://pramitmarattha.com.np/22-best-dataops-tools-to-optimize-your-data-management-and-observability-in-2023</link><guid isPermaLink="true">https://pramitmarattha.com.np/22-best-dataops-tools-to-optimize-your-data-management-and-observability-in-2023</guid><category><![CDATA[data]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Thu, 02 Feb 2023 11:20:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675335306839/60932bc8-938d-44a1-8d23-52a25fda69f1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The data landscape is rapidly evolving, and the amount of data being produced and distributed on a daily basis is downright staggering. According to the report by <a target="_blank" href="https://www.statista.com/statistics/871513/worldwide-data-created/">Statista</a>, currently, there are approximately 120 zettabytes of data in existence (as of 2023), and this number is projected to reach 181 zettabytes by 2025.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/legnbvljdu1r308yzmce.png" alt="Volume of data created and consumed globally from 2010 to 2020, with forecasts from 2021 to 2025 (in zettabytes). (Source: statista.com)" /></p>
<p>As the volume of data continues to expand rapidly, so does the demand for efficient data management and observability solutions and tools. The actual value of data lies in how it is being utilized. Collecting and storing data alone is not enough; it must be leveraged and used correctly to get valuable insights. These insights can range from demographics to consumer behavior and even future sales predictions, providing an unparalleled resource for business decision-making processes. Also, with real-time data, businesses can make quick and informed decisions, adapt to the market and capitalize on live opportunities. However, this is only possible if data is of good quality, outdated, misleading, or difficult to access, which is precisely where DataOps comes to the rescue and plays a crucial role in optimizing and streamlining data management processes.</p>
<h2 id="heading-unpacking-the-essence-of-dataops"><strong>Unpacking the essence of DataOps</strong></h2>
<p><a target="_blank" href="https://www.chaosgenius.io/blog/dataops-101-an-introduction-to-this-essential-approach-to-data-management/"><strong>DataOps</strong></a> is a set of best practices and tools that aims to enhance the collaboration, integration, and automation of data management operations and tasks. DataOps seeks to improve the quality, speed, and collaboration of data management through an integrated and process-oriented approach, utilizing automation and agile software engineering practices similar to that of DevOps to speed up and streamline the process of accurate data delivery [1]. It is designed to help businesses and organizations better manage their data pipelines, reduce the workload and time required to develop and deploy new data-driven applications and improve the quality of the data being used.</p>
<p>Now that we have a clear understanding of what DataOps means let's delve deeper into its key components. The key components of a DataOps strategy include data integration, data quality management and measurement, data governance, data orchestration, and DataOps Observability.</p>
<h3 id="heading-data-integration"><strong>Data integration</strong></h3>
<p>Data integration involves integrating and testing code changes and promptly deploying them to production environments, ensuring accuracy and consistency of data as it is integrated and delivered to appropriate teams.</p>
<h3 id="heading-data-quality-management"><strong>Data quality management</strong></h3>
<p>Data Quality Management involves identifying, correcting, and preventing errors or inconsistencies in data, ensuring that the data being used is highly reliable and accurate.</p>
<h3 id="heading-data-governance"><strong>Data governance</strong></h3>
<p>Data governance ensures that data is collected, stored, and used consistently, ethically and complies with regulations.</p>
<h3 id="heading-data-orchestration"><strong>Data orchestration</strong></h3>
<p>Data orchestration helps to manage and coordinates data processing in a pipeline, specifying and scheduling tasks and dealing with errors to automate and optimize data flow through the data pipeline. It is crucial for ensuring the smooth operation and performance of the data through the data pipeline.</p>
<h3 id="heading-dataops-observability"><strong>DataOps observability</strong></h3>
<p>DataOps observability refers to the ability to monitor and understand the various processes and systems involved in data management, with the primary goal of ensuring the reliability, trustworthiness, and business value of the data. It involves everything from monitoring and analyzing data pipelines to maintaining data quality and proving the data's business value through financial and operational efficiency metrics. DataOps observability allows businesses and organizations to improve the efficiency of their data management processes and make better use of their data assets. It aids in ensuring that data is always correct, dependable, and easily accessible, which in turn helps businesses and organizations make data-driven decisions, optimize data-related costs/spend and generate more value from it.</p>
<h2 id="heading-top-dataops-and-dataops-observability-tools-to-simplify-data-management-cost-amp-collaboration-processes"><strong>Top DataOps and DataOps Observability tools to simplify data management, cost &amp; collaboration processes</strong></h2>
<p>One of the most challenging aspects of DataOps is integrating data from various sources and ensuring data quality, orchestration, observability, data cost management, and governance. DataOps aims to streamline these processes and improve collaboration among teams, enabling businesses to make better data-driven decisions and achieve improved performance and results [2]. In this article, we will focus on DataOps observability and the top DataOps tools businesses can use to streamline their data management, costs, and collaboration processes.</p>
<p>A wide variety of DataOps tools are available on the market, and choosing the right one can be a very daunting task. To help businesses make an informed decision, this article has compiled a list of the <strong><em>top</em></strong> DataOps tools that can be used to manage data-driven processes.</p>
<hr />
<h2 id="heading-data-integration-tools"><strong>Data Integration Tools</strong></h2>
<p><strong>1)</strong> <a target="_blank" href="https://www.fivetran.com/"><strong>Fivetran</strong></a></p>
<p><a target="_blank" href="https://www.fivetran.com/">Fivetran</a> is a very popular and widely adopted data integration platform that simplifies the process of connecting various data sources to a centralized data warehouse [3]. This enables users or businesses to easily analyze and visualize their data in one place, eliminating the need to manually extract, transform, and load (ETL) data from multiple different sources.</p>
<p>Fivetran provides sets of <a target="_blank" href="https://www.fivetran.com/connectors">pre-built connectors</a> for a wide range of data sources, including popular databases, cloud applications, SaaS applications—and even flat files. These connectors automate the process of data extraction, ensuring that the data is always up-to-date, fresh and accurate. Once data is in the central data warehouse, Fivetran performs schema discovery and data validation, automatically creating tables and columns in the data warehouse based on the structure of the data source, making it really very easy to set up and maintain data pipelines without the need for manually writing custom code.</p>
<p>Fivetran also offers features like data deduplication, incremental data updates, and real-time data replication. These features help make sure that the data is always complete, fresh and accurate.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23orwukxb4c0vp0ukgx4.png" alt="How Fivetran features manage data. (Source: fivetran.com)" /></p>
<p><strong>2)</strong> <a target="_blank" href="https://www.talend.com/products/data-fabric/"><strong>Talend Data Fabric</strong></a></p>
<p><a target="_blank" href="https://www.talend.com/products/data-fabric/">Talend Data Fabric</a> solution is designed to help businesses and organizations make sure they have healthy data to stay in control, mitigate risk, and drive massive value. The platform combines <a target="_blank" href="https://www.talend.com/products/integrate-data/">data integration</a>, <a target="_blank" href="https://www.talend.com/products/data-quality/">integrity</a>, and <a target="_blank" href="https://www.talend.com/products/data-integrity-governance/">governance</a> to deliver reliable data that businesses and organizations can rely on for decision-making processes. Talend helps businesses build customer loyalty, improve operational efficiency and modernize their IT infrastructure.</p>
<p>Talend's unique approach to <a target="_blank" href="https://www.talend.com/products/integrate-data/">data integration</a> makes it easy for businesses and organizations to bring data together from multiple sources and power all their business decisions. It can integrate virtually any data type from any data source to any data destination(on-premises or in the cloud). The platform is flexible, allowing businesses and organizations to build data pipelines once and run them anywhere, with no vendor or platform lock-in. And the solution is an all-in-one (unified solution), bringing together data integration, data quality, and data sharing on an easy-to-use platform.</p>
<p>Talend's Data Fabric offers a multitude of best-in-class data integration capabilities, such as <a target="_blank" href="https://www.talend.com/products/data-integration/">Data Integration</a>, <a target="_blank" href="https://www.talend.com/products/cloud-pipeline-designer/">Pipeline Designer</a>, <a target="_blank" href="https://www.talend.com/products/data-inventory/">Data Inventory</a>, <a target="_blank" href="https://www.talend.com/products/data-preparation/">Data Preparation</a>, <a target="_blank" href="https://www.talend.com/products/change-data-capture/">Change Data Capture</a>, and <a target="_blank" href="https://www.talend.com/products/data-loader/">Data Stitching</a>. These tools make data integration, data discovery/search and data sharing more manageable, enabling users to prepare and integrate data quickly, visualize it, keep it fresh, and move it securely.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tjkjgg8nzp1h2d2krsfk.png" alt="Talend (Source: talend.com)" /></p>
<p><strong>3)</strong> <a target="_blank" href="https://streamsets.com/"><strong>StreamSets</strong></a></p>
<p><a target="_blank" href="https://streamsets.com/">StreamSets</a> is a powerful data integration platform that allows businesses to control and manage data flow from a variety of batch and streaming sources to modern analytics platforms. You can deploy and scale your dataflows on-edge, on-premises, or in the cloud using its collaborative, visual pipeline design, while also mapping and monitoring them for end-to-end visibility[4]. The platform also allows for the enforcement of <a target="_blank" href="https://databand.ai/blog/what-is-a-data-sla/">Data SLAs</a> for high availability, quality, and privacy. StreamSets enables businesses and organizations to quickly launch projects by eliminating the need for specialized coding skills through its visual pipeline design, testing, and deployment features, all of which are accessible via an intuitive graphical user interface. With StreamSets, brittle pipelines and lost data will no longer be a concern, as the platform can automatically handle unexpected changes. The platform also includes a live map with metrics, alerting, and drill-down functionality, allowing businesses to efficiently integrate data in a breeze.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/adklx3d1x5numltgrguh.png" alt="StreamSets (Source: streamsets.com)" /></p>
<p><strong>4)</strong> <a target="_blank" href="https://www.k2view.com/"><strong>K2View</strong></a></p>
<p><a target="_blank" href="https://www.k2view.com/">K2View</a> provides enterprise-level DataOps tools. It offers a <a target="_blank" href="https://www.k2view.com/what-is-data-fabric">data fabric platform</a> for real-time data integration, which enables businesses and organizations to deliver personalized experiences [6]. K2View's enterprise-level <a target="_blank" href="https://www.k2view.com/platform/data-integration-tools/">data integration tools</a> integrate data from any kind of source and make it accessible to any consumer through various methods such as bulk <a target="_blank" href="https://www.chaosgenius.io/blog/data-engineering-and-dataops-beginners-guide-to-building-data-solutions-and-solving-real-world-challenges/">ETL</a>, reverse ETL, data streaming, data virtualization, log-based <a target="_blank" href="https://en.wikipedia.org/wiki/Change_data_capture">CDC</a>, message-based integration, SQL—and APIs.</p>
<p>K2View can ingest data from various sources and systems, enhance it with real-time insights, convert it into its patented <a target="_blank" href="https://www.k2view.com/platform/micro-database">micro-database</a>, and ensure performance, scalability, and security by compressing and encrypting the micro-database individually. It then applies <a target="_blank" href="https://www.k2view.com/platform/data-masking-tools/">data masking</a>, transformation, enrichment, and <a target="_blank" href="https://www.k2view.com/platform/data-masking-tools/">orchestration tools</a> on-the-fly to make the data accessible to authorized consumers in any format while adhering to data privacy and security rules.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thadu4fztjgtocm833np.png" alt="K2VIEW (Source: k2view.com)" /></p>
<p><strong>5)</strong> <a target="_blank" href="https://www.alteryx.com/"><strong>Alteryx</strong></a></p>
<p><a target="_blank" href="https://www.alteryx.com/">Alteryx</a> is a very powerful data integration platform that allows users to easily access, manipulate, analyze, and output data. The platform utilizes a drag-and-drop interface (low code/no code interface) and includes a variety of tools and connectors(80+) for data blending, predictive analytics, and data visualization[7]. It can be used in a one-off manner or, more commonly, as a recurring process called a "<strong>workflow</strong>." The way Alteryx builds workflows also serves as a form of process documentation, allowing users to view, collaborate, support and enhance the process. The platform can read and write data to files, databases, and APIs, and it also includes functionality for predictive analytics and geospatial analysis. Alteryx is currently being used in a variety of industries and functional areas and can be used to more quickly and efficiently automate data integration processes. Some common use cases include combining and manipulating data within spreadsheets, supplementing SQL development, APIs, cloud or hybrid access, data science, geospatial analysis—and creating reports and dashboards.</p>
<blockquote>
<p>Note: Alteryx is often compared to ETL tools, but it is important to remember that its primary audience is data analysts. Alteryx aims to empower business users by giving them the freedom to access, manipulate, and analyze data without relying on IT.</p>
</blockquote>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2conwxxcpckyc4tvfteq.png" alt="Alteryx (Source: alteryx.com)" /></p>
<hr />
<h2 id="heading-data-quality-testing-and-monitoring-tools"><strong>Data Quality Testing and Monitoring Tools</strong></h2>
<p><strong>1)</strong> <a target="_blank" href="https://www.montecarlodata.com/"><strong>Monte Carlo</strong></a></p>
<p>Monte Carlo is a leading enterprise data monitoring and observability platform. It provides an end-to-end solution for monitoring and alerting for data issues across the data warehouses, data lakes, ETL, and business intelligence platforms. It uses machine learning and AI to learn about the data and proactively identify data-related issues, assess their impact, and notify those who need to know. The platform's automatic and immediate identification of the root cause of issues allows teams to collaborate and resolve problems faster, and it also provides automatic, <a target="_blank" href="https://www.montecarlodata.com/blog-announcing-monte-carlos-end-to-end-field-level-lineage-to-help-teams-achieve-data-trust/">field-level lineage</a> , data discovery, and centralized data cataloging that allows teams to better understand the accessibility, location, health, and ownership of their data assets. The platform is designed with security in mind, scales accordingly with the provided stack, and includes a no-code or low-code(code-free) onboarding feature for easy implementation with the existing data stack.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b68rh8qzt51sb9xlmmnr.png" alt="Monte Carlo (Source: montecarlodata.com)" /></p>
<p><strong>2)</strong> <a target="_blank" href="https://databand.ai/"><strong>Databand</strong></a></p>
<p><a target="_blank" href="https://databand.ai/">Databand</a> is a data monitoring and observability platform recently acquired by IBM that helps organizations detect and resolve data issues before they impact the business. It provides a fierce, end-to-end view of data pipelines, starting with source data, which allows businesses and organizations to detect and resolve issues early, reducing the <a target="_blank" href="https://www.techtarget.com/searchitoperations/definition/mean-time-to-detect-MTTD">mean time to detection</a> (MTTD) and <a target="_blank" href="https://www.atlassian.com/incident-management/kpis/common-metrics">mean time to resolution</a> (MTTR) from days and weeks to minutes.</p>
<p>One key features of Databand is its ability to automatically collect <a target="_blank" href="https://twitter.com/startdataeng/status/1612448003368882176">metadata</a> from modern data stacks such as <a target="_blank" href="https://airflow.apache.org/">Airflow</a>, <a target="_blank" href="https://spark.apache.org/">Spark</a>, <a target="_blank" href="https://www.databricks.com/">Databricks</a>, <a target="_blank" href="https://aws.amazon.com/redshift/">Redshift</a>, <a target="_blank" href="https://www.getdbt.com/">dbt</a>, and <a target="_blank" href="https://www.snowflake.com/en/">Snowflake</a>. This <a target="_blank" href="https://twitter.com/startdataeng/status/1612448003368882176">metadata</a> is used to build historical baselines of common data pipeline behavior, which allows organizations to get visibility into every data flow from source to destination.</p>
<p><img src="https://www.chaosgenius.io/blog/content/images/2023/01/image.png" alt="https://www.chaosgenius.io/blog/content/images/2023/01/image.png" /></p>
<p>Databand also provides incident management, end-to-end lineage, data reliability monitoring, data quality metrics, anomaly detection, and DataOps alerting and routing capabilities. With this, businesses and organizations can improve data reliability and quality and visualize how data incidents impact upstream and downstream components of the data stack. Databand's combined capabilities provide a single solution for all data incidents, allowing engineers to focus on building their modern data stack rather than fixing it.</p>
<p><strong>3)</strong> <a target="_blank" href="https://www.datafold.com/"><strong>Data Fold</strong></a></p>
<p><a target="_blank" href="https://www.datafold.com/">Datafold</a> is a data reliability platform focused on proactive data quality management that helps businesses prevent data catastrophes. It has the unique ability to detect, evaluate, and investigate data quality problems before they impact productivity. The platform offers real-time monitoring to identify issues quickly and prevent them from becoming data catastrophes.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbzjrzrgrgum1hjtmw09.png" alt="Datafold dashboard. (Source: datafold.com)" /></p>
<p>Datafold harnesses the power of machine learning with AI to provide analytics with real-time insights, allowing data engineers to make top-quality predictions from large amounts of data.</p>
<p><strong>Some of the key features of Datafold include:</strong></p>
<ul>
<li><p>One-Click Regression Testing for ETL</p>
</li>
<li><p>Data flow visibility Across all pipelines and BI reports</p>
</li>
<li><p>SQL Query Conversion, Data Discovery, and Multiple data source Integrations</p>
</li>
</ul>
<p>Datafold offers a simple yet intuitive user interface(UI) and navigation with powerful features. The platform allows deep exploration of how tables and data assets relate. The visualizations are really very easy to understand. Data quality monitoring is also super flexible. However, the data integrations they support are relatively limited.</p>
<h3 id="heading-4-query-surgehttpswwwquerysurgecom"><strong>4)</strong> <a target="_blank" href="https://www.querysurge.com/"><strong>Query Surge</strong></a></h3>
<p><a target="_blank" href="https://www.querysurge.com/">QuerySurge</a> is a very powerful/versatile tool for automating data quality testing and monitoring, particularly for big data, data warehouses, BI reports, and enterprise-level applications. It is particularly designed to integrate seamlessly, allowing for continuous testing and validation of data as it flows.</p>
<p>Query Surge also provides the ability to create and run tests without needing to write SQL through smart query wizards. This allows for column, table, and row-level comparisons and automatic column matching. Also, users can create custom tests that can be modularized with reusable "<strong>snippets</strong>" of code, set thresholds, check data types, and perform other advanced number of validation checks. QuerySurge also has robust scheduling capabilities, allowing users to run tests pronto, at a specified date and time. On top of that, it also supports <a target="_blank" href="https://www.querysurge.com/product-tour/features#supported-technologies">200+ supported vendors and tech stacks</a>, so it can test across a wide variety of platforms, including big data lakes, data warehouses, traditional databases, NoSQL document stores, BI reports, flat files, JSON files—and a whole lot more.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/orcxh5acep417efp2v0z.png" alt="Query Surge (Source: querysurge.com)" /></p>
<p>One key benefits of QuerySurge is its ability to integrate with other solutions in the DataOps pipeline, such as data integration/ETL solutions, build/configuration solutions, QA and test management solutions. The tool also includes a Data Analytics Dashboard, which allows users to monitor test execution progress in real-time, drill down into data to examine results, and see stats for executed tests. It also has an out-of-the-box integration with plethora of <a target="_blank" href="https://www.querysurge.com/partner-program/partners">services</a> and any other solution with API access.</p>
<p>QuerySurge is available both on-premises and in the cloud, with support for <a target="_blank" href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES 256-bit encryption</a>, <a target="_blank" href="https://jumpcloud.com/blog/ldap-vs-ldaps">LDAP/LDAPS</a>, TLS, HTTPS/SSL, auto-timeout, and other security features. In a nutshell, QuerySurge is a very powerful and comprehensive solution for automating data monitoring and testing, allowing businesses and organizations to improve their data quality at speed and reduce the risk of data-related issues in the delivery pipeline.</p>
<h3 id="heading-5-right-datahttpsgetrightdatacomrdt-product"><strong>5)</strong> <a target="_blank" href="https://getrightdata.com/RDt-product"><strong>Right Data</strong></a></h3>
<p>Right Data's <a target="_blank" href="https://getrightdata.com/RDt-product">RDT</a> is a powerful data testing and monitoring platform that helps businesses and organizations improve the reliability and trust of their data by providing an easy-to-use interface for data testing, reconciliation, and validation. It allows users to quickly identify issues related to data consistency, quality, and completeness. It also provides an efficient way to analyze, design, build, execute and automate reconciliation and validation scenarios with little to no coding required, which helps save time and resources.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzd09gp8j6kl1504ltst.png" alt="Right Data (Source: getrightdata.com/RDt-product)" /></p>
<p><strong>Key features of RDT:</strong></p>
<ul>
<li><p><strong>Ability to analyze DB</strong>: It provides a full set of applications to analyze the source and target datasets. Its top-of-the-line Query Builder and Data Profiling features help users understand and analyze the data before they use the corresponding datasets in different scenarios.</p>
</li>
<li><p><strong>Support of a wide range of data sources</strong>: RDT supports a wide range of data sources such as <a target="_blank" href="https://www.microfocus.com/documentation/xdbc/win20/BKXDXDINTRXD1.5.html">ODBC or JDBC</a>, flat files, cloud technologies, SAP, big data, BI reporting—and various other sources. This allows businesses and organizations to easily connect to and work with their existing data source.</p>
</li>
<li><p><strong>Data reconciliation</strong>: RDT has features like "<strong>Compare Row Counts</strong>" that let users compare the number of rows in the source dataset and the target dataset and find tables where the number of rows doesn't match. It also provides a "<strong>row-level data compare</strong>" feature that compares datasets between source/target and identifies rows that do not match each other.</p>
</li>
<li><p><strong>Data Validation:</strong> RDT provides a user-friendly interface for creating validation scenarios, which enables users to establish one or more validation rules for target data sets, identify exceptions, and analyze and report on the results.</p>
</li>
<li><p><strong>Admin &amp; CMS:</strong> RDT has an admin console that allows the admin to manage and config the features of the tool. The console provides the ability to create + manage users, roles, and the mapping of roles to specific users. Administrators can also create, manage, and test connection profiles, which are used to create queries. The tool also provides a Content Management Studio (CMS) that enables exporting of queries, scenarios, and connection profiles from one RightData instance to another. This feature is useful for copying within the same instance from one folder to another and also for switching over the connection profile of queries.</p>
</li>
</ul>
<hr />
<h2 id="heading-dataops-observability-and-augmented-finops"><strong>DataOps Observability and Augmented FinOps</strong></h2>
<p><strong>1)</strong> <a target="_blank" href="https://www.chaosgenius.io/"><strong>Chaos Genius</strong></a></p>
<p><a target="_blank" href="https://www.chaosgenius.io/">Chaos Genius</a> is a powerful <a target="_blank" href="https://www.chaosgenius.io/blog/dataops-101-an-introduction-to-this-essential-approach-to-data-management/">DataOps</a> Observability tool that uses ML and AI to provide precise cost projections and enhanced metrics for monitoring and analyzing data and business metrics. One of the main reasons the tool was built was to provide value to businesses by offering a powerful, first-in-class DataOps observability tool that can help monitor and analyze data, lower spending, and improve business metrics. The tool utilizes machine learning and artificial intelligence (ML/AI) to sift through data and provide more precise cost projections and enhanced metrics.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wiffrcieiggzhrqx0xqm.png" alt="Chaos Genius (Source: chaosgenius.io)" /></p>
<p>Chaos Genius currently offers a service called "<strong>Snowflake Observability</strong>" as one of its main services.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvmsj84rzj2lcqthfk2o.png" alt="Chaos Genius Snowflake Observability (Source: chaosgenius.io)" /></p>
<p>Key features of Chaos Genius (<strong>Snowflake Observability</strong>) include:</p>
<ul>
<li><p><strong>Cost optimization and monitoring:</strong> Chaos Genius is designed to help businesses and organizations optimize and monitor the cost of a Snowflake cloud data platform. This includes finding places where costs can be cut and making suggestions for how to do so.</p>
</li>
<li><p><strong>Enhanced query performance:</strong> Chaos Genius can analyze query patterns to identify inefficient queries and make smart recommendations to improve their performance, which can lead to faster and more efficient data retrieval and improve the overall performance of the data warehouse.</p>
</li>
<li><p><strong>Reduced Spendings</strong>: Chaos Genius enables businesses to better enhance the efficiency of their systems and reduce total spending by about <strong>~10% - 30%</strong>.</p>
</li>
<li><p><strong>Affordability:</strong> Chaos Genius offers an affordable pricing model with three tiers. The first tier is completely free, while the other two are business-oriented plans for companies that want to monitor more metrics. This makes it accessible to businesses of all sizes and budgets.</p>
</li>
</ul>
<h3 id="heading-2-unravelhttpswwwunraveldatacom"><strong>2)</strong> <a target="_blank" href="https://www.unraveldata.com/"><strong>Unravel</strong></a></h3>
<p><a target="_blank" href="https://www.unraveldata.com/">Unravel</a> is a DataOps observability platform that provides businesses and organizations with a thorough view of their entire data stack and helps them optimize performance, automate troubleshooting, and manage and monitor the cost of their entire data pipelines. The platform is also designed to work with different cloud service providers, for example, <a target="_blank" href="https://www.unraveldata.com/azure-databricks/">Azure</a>, <a target="_blank" href="https://www.unraveldata.com/amazon-emr/">Amazon EMR</a>, <a target="_blank" href="https://www.unraveldata.com/google-cloud-gcp/">GCP</a>, <a target="_blank" href="https://www.unraveldata.com/cloudera/">Cloudera</a> and even <a target="_blank" href="https://www.unraveldata.com/integrations/">on-premises environments</a>, providing businesses with the flexibility to manage their data pipeline regardless of where their data resides.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lj9pzah4s61xg93hu59m.png" alt="Unravel Data (Source: unraveldata.com)" /></p>
<p>Unravel uses the power of machine learning and AI to model data pipelines from end to end, providing businesses with a detailed understanding of how data flows through their systems. This enables businesses/organizations to identify bottlenecks, optimize resource allocation and improve the overall performance of their data pipelines.</p>
<p>The platform's data model enables businesses to explore, correlate, and analyze data across their entire environment, providing deep insights into how apps, services, and resources are used and what works and what doesn't, allowing businesses to quickly identify potential issues and take immediate action to resolve them. Not only that, but Unravel also has automatic troubleshooting features that can help businesses find the cause of a problem quickly and take steps to fix it, saving them a huge amount of spending and making their data pipelines more reliable and efficient.</p>
<hr />
<h3 id="heading-data-orchestration-tools"><strong>Data Orchestration Tools</strong></h3>
<p><strong>1)</strong> <a target="_blank" href="https://airflow.apache.org/"><strong>Apache Airflow</strong></a></p>
<p><a target="_blank" href="https://airflow.apache.org/">Apache Airflow</a> is a fully open source DataOps workflow orchestration tool to author, schedule, and monitor workflows programmatically. Airbnb first developed it, but now it is under the Apache Software Foundation [8]. It is a tool for expressing and managing data pipelines and is often used in data engineering. It allows users to define, schedule, and monitor workflows as <a target="_blank" href="https://www.tutorialspoint.com/directed-acyclic-graph-dag">directed acyclic graphs (DAGs)</a> of tasks. Airflow provides a simple and powerful way to manage data pipelines, and it is simple to use, allowing users to create and manage complex workflows quickly; on top of that, it has a large and active community that provides many plugins, connectors, and integrations with other tools that makes it very versatile.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6f1f1sc9bf8lo6e5enz3.png" alt="Apache Airflow (Source: airflow.apache.org)" /></p>
<p>Key features of Airflow include:</p>
<ul>
<li><p><strong>Dynamic pipeline generation</strong>: Airflow's <a target="_blank" href="https://medium.com/apache-airflow/creating-dynamic-sourcing-pipelines-introduction-and-overview-1-3-1aa45234c863">dynamic pipeline generation</a> is one of its key features. Airflow allows you to define and generate pipelines programmatically rather than manually creating and managing them. This facilitates the creation and modification of complex workflows.</p>
</li>
<li><p><strong>Extensibility:</strong> Airflow allows using custom plugins, <a target="_blank" href="https://airflow.apache.org/docs/apache-airflow/stable/concepts/operators.html">operators</a> and <a target="_blank" href="https://airflow.apache.org/docs/apache-airflow/stable/executor/index.html">executors</a>, which means you can add new functionality to the platform to suit your specific needs and requirements; this makes Airflow highly extensible and an excellent choice for businesses and organizations with unique requirements or working with complex data pipelines.</p>
</li>
<li><p><strong>Scalability:</strong> Airflow has built-in support for <a target="_blank" href="https://medium.com/vedity/apache-airflow-scaling-a-dag-679934285403">scaling thousands of tasks</a>, making it very well-suited for large-scale organizations or running large-scale data processing tasks.</p>
</li>
</ul>
<p><strong>2)</strong> <a target="_blank" href="https://www.shipyardapp.com/"><strong>Shipyard</strong></a></p>
<p><a target="_blank" href="https://www.shipyardapp.com/">Shipyard</a> is a powerful data orchestration tool designed to help data teams streamline and simplify their workflows and deliver data at very high speed. The tool is intended to be code-agnostic, allowing teams to deploy code in any language they prefer without the need for a steep learning curve. It is cloud-ready, meaning it eliminates the need for teams to spend hours and hours spinning up and managing their servers. Instead, they can orchestrate their workflows in the cloud, allowing them to focus on what they do best—working with data. Shipyard can also run thousands of jobs at once, making it ideal for scaling data processing tasks. The tool can dynamically scale to meet the demand, ensuring that workflows run smoothly and efficiently even when dealing with large amounts of data.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/omci1nm995wyyj453ltj.png" alt="Shipyard (Source: shipyardapp.com)" class="image--center mx-auto" /></p>
<p>Shipyard comes with a very intuitive visual UI, allowing users to construct workflows directly from the interface and make changes as needed by dragging and dropping. The advanced scheduling, webhooks and on-demand triggers make automating workflows on any schedule easy. It also allows for cross-functional workflows, meaning that the entire data process can be interconnected across the entire data lifecycle, helping teams keep track of the entire data journey, from data collection and processing to visualization and analysis.</p>
<p>Shipyard also provides instant notifications, which help teams catch and fix critical breakages before anyone even notices. It also has automatic retries and cutoffs, which give workflows resilience, so teams don't have to lift a finger. Not only that, it can isolate and address the root cause in real time, so teams can get back up and running in seconds. Also, it allows teams to connect their entire data stack in minutes, seamlessly moving data between the existing tools in the data stack, regardless of the cloud provider. With over <a target="_blank" href="https://www.shipyardapp.com/integrations">20+ integrations and 60+ low-code templates</a> to choose from, data teams can begin connecting their existing tools in record speeed!!!</p>
<p><strong>3)</strong> <a target="_blank" href="https://dagster.io/"><strong>Dagster</strong></a></p>
<p><a target="_blank" href="https://dagster.io/">Dagster</a> is a next-generation open source data orchestration platform for developing, producing, and observing data assets in real-time. Its primary focus is to provide a unified experience for data engineers, data scientists, and developers to manage the entire lifecycle of data assets, from development and testing to production and monitoring. Using Dagster, users can manage their data assets with code and monitor "runs" across all jobs in one place with the <strong>run timeline view</strong>. On the other hand, the <strong>run details view</strong> allows users to zoom into a run and pin down issues with surgical precision.</p>
<p>Dagster also allows users to see each asset's context and update it all in one place, including <a target="_blank" href="https://docs.dagster.io/concepts/assets/asset-materializations">materializations</a>, lineage, schema, schedule, partitions—and a whole lot more. Not only that, but it also allows users to launch and monitor backfills over every partition of data. Dagster is an enterprise-level orchestration platform that prioritizes developer experience(DX) with fully serverless + hybrid deployments, native branching, and provides out-of-the-box CI/CD configuration.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/77ouqi3hscf6ehkjaa09.png" alt="Dagster (Source: dagster.io)" /></p>
<p><strong>4)</strong> <a target="_blank" href="https://aws.amazon.com/glue/"><strong>AWS glue</strong></a></p>
<p>AWS Glue is a data orchestration tool that makes it easy to discover, prepare, and combine data for analytics and machine learning workflows. With Glue, you can crawl data sources, extract, transform and load (ETL) data, and create/schedule data pipelines using a simple visual UI interface. Glue can also be used for analytics and includes tools for authoring, running jobs, and implementing business workflows. AWS Glue offers data discovery, ETL, cleansing, and central cataloging and allows you to connect to over <a target="_blank" href="https://docs.aws.amazon.com/glue/latest/dg/components-overview.html">70 diverse data sources</a> [9]. You can create, run and monitor ETL pipelines to load data into data lakes and query cataloged data using Amazon Athena, Amazon EMR, and Redshift Spectrum. It is serverless in nature, meaning there's no infrastructure to manage, and it supports all kinds of workloads like ETL, ELT, and streaming all packaged in one service. AWS Glue is very user-friendly and is suitable for all kinds of users, including developers and business users. Its ability to scale on demand allows users to focus on high-value activities that extract maximum value from their data; it can handle any data size and support all types of data and schema variations.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1iu6zzsbn6e4j56ebn3j.png" alt="AWS Glue (Source: aws.amazon.com/glue)" class="image--center mx-auto" /></p>
<p>AWS Glue provides TONS of awesome features that can be used in a DataOps workflow, such as:</p>
<ul>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/glue/latest/dg/catalog-and-crawler.html"><strong>Data Catalog</strong></a><strong>:</strong> A central repository to store structural and operational metadata for all data assets.</p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/glue/latest/ug/creating-jobs-chapter.html"><strong>ETL Jobs:</strong></a> The ability to define, schedule, and run ETL jobs to prepare data for analytics.</p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/glue/latest/dg/add-crawler.html"><strong>Data Crawlers:</strong></a> Automated data discovery and classification that can connect to data sources, extract metadata, and create table definitions in the Data Catalog.</p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/glue/latest/dg/add-classifier.html"><strong>Data Classifiers:</strong></a> The ability to recognize and classify specific types of data, such as JSON, CSV, and Parquet.</p>
</li>
<li><p><a target="_blank" href="https://www.analyticsvidhya.com/blog/2021/01/using-aws-data-wrangler-with-aws-glue-job-2-0/"><strong>Data Wrangler:</strong></a> A visual data transformation tool that makes it easy to clean and prepare data for analytics.</p>
</li>
<li><p><strong>Security</strong>: Integrations with <a target="_blank" href="https://aws.amazon.com/iam/">AWS Identity and Access Management (IAM)</a> and <a target="_blank" href="https://aws.amazon.com/vpc/">Amazon Virtual Private Cloud</a> (VPC) to help secure data in transit and at rest.</p>
</li>
<li><p><strong>Scalability</strong>: The ability to handle petabyte-scale data and thousands of concurrent ETL jobs.</p>
</li>
</ul>
<hr />
<h2 id="heading-data-governance-tools"><strong>Data Governance Tools</strong></h2>
<p><strong>1)</strong> <a target="_blank" href="https://www.collibra.com/us/en"><strong>Collibra</strong></a></p>
<p><a target="_blank" href="https://www.collibra.com/us/en">Collibra</a> is an enterprise-oriented data governance tool that helps businesses and organizations understand and manage their data assets. It enables businesses and organizations to create an inventory of data assets, capture metadata about 'em, and govern these assets to ensure regulatory compliance. The tool is primarily used by IT, data owners, and administrators who are in charge of data protection and compliance to inventory and track how data is used. Collibra's main aim is to protect data, ensure it is appropriately governed and used, and eliminate potential fines and risks from a lack of regulatory compliance.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulo4xpto14fk434x8410.png" alt="Collibra (Source: collibra.com)" /></p>
<p><strong>Collibra offers six key functional areas to aid in data governance:</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/data-quality-and-observability"><strong>Collibra Data Quality &amp; Observability</strong></a>: Monitors data quality and pipeline reliability to aid in remedying anomalies.</p>
</li>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/data-catalog"><strong>Collibra Data Catalog</strong></a>: A single solution for finding and understanding data from various sources.</p>
</li>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/data-governance"><strong>Data Governance</strong></a>: A location for finding, understanding, and creating a shared language around data for all individuals within an organization.</p>
</li>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/data-lineage"><strong>Data Lineage</strong></a>: Automatically maps relationships between systems, applications, and reports to provide a comprehensive view of data across the enterprise.</p>
</li>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/protect"><strong>Collibra Protect</strong></a>: Allows for the discovery, definition, and protection of data from a unified platform.</p>
</li>
<li><p><a target="_blank" href="https://www.collibra.com/us/en/products/data-privacy"><strong>Data Privacy</strong></a>: Centralizes, automates, and guides workflows to encourage collaboration and address global regulatory requirements for data privacy.</p>
</li>
</ul>
<p><strong>2)</strong> <a target="_blank" href="https://www.alation.com/"><strong>Alation</strong></a></p>
<p><a target="_blank" href="https://www.alation.com/">Alation</a> is an enterprise-level data catalog tool that serves as a single reference point for all of an organization's data. It automatically crawls and indexes over 60 different data sources, including on-premises databases, cloud storage, file systems, and BI tools. Using query log ingestion, Alation parses queries to identify the most frequently used data and the individuals who use it the most, forming the basis of the catalog. Users can then collaborate and provide context for the data. With the catalog in place, data analysts and scientists can quickly and easily locate, examine, verify, and reuse data, hence boosting their productivity. Alation can also be used for data governance, allowing analytics teams to efficiently manage and enforce policies for data consumers.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ht4gjzup6gby3zkyyvdl.png" alt="Alation (Source: Alation)" class="image--center mx-auto" /></p>
<p><strong>Key benefits of using Alation:</strong></p>
<ul>
<li><p>Boost analyst productivity</p>
</li>
<li><p>Improve data comprehension</p>
</li>
<li><p>Foster collaboration</p>
</li>
<li><p>Minimize the risk of data misuse</p>
</li>
<li><p>Eliminate IT bottlenecks</p>
</li>
<li><p>Easily expose and interpret data policies</p>
</li>
</ul>
<p>Alation offers various solutions to improve productivity, accuracy and data-driven decision-making. These include:</p>
<ul>
<li><p><a target="_blank" href="https://www.alation.com/product/data-catalog/"><strong>Alation Data Catalog</strong></a>: Improves the efficiency of analysts and the accuracy of analytics, empowering all members of an organization to find, understand, and govern data efficiently.</p>
</li>
<li><p><a target="_blank" href="https://www.alation.com/product/connectors/"><strong>Alation Connectors</strong></a><strong>:</strong> A wide range of native data sources that speed up the process of gaining insights and enable data intelligence throughout the enterprise. (Additional data sources can also be connected with the Open Connector Framework SDK.)</p>
</li>
<li><p><a target="_blank" href="https://www.alation.com/product/platform/"><strong>Alation Platform</strong></a>: An open and intelligent solution for various metadata management applications, including search and discovery, data governance, and digital transformation.</p>
</li>
<li><p><a target="_blank" href="https://www.alation.com/product/data-governance-app/"><strong>Alation Data Governance App</strong></a><strong>:</strong> Simplifies secure access to the best data in hybrid and multi-cloud environments.</p>
</li>
<li><p><a target="_blank" href="https://www.alation.com/product/cloud-service/"><strong>Alation Cloud Service</strong></a><strong>:</strong> Offers businesses and organizations the option to manage their data catalog on their own or have it managed for them in the cloud.</p>
</li>
</ul>
<hr />
<h2 id="heading-data-cloud-and-data-lake-platforms"><strong>Data Cloud and Data Lake Platforms</strong></h2>
<p><strong>1).</strong> <a target="_blank" href="https://www.databricks.com/"><strong>Databricks</strong></a></p>
<p><a target="_blank" href="https://www.databricks.com/">Databricks</a> is a cloud-based lakehouse platform founded in 2013 by the creators of <a target="_blank" href="https://spark.apache.org/">Apache Spark</a>, <a target="_blank" href="https://delta.io/">Delta Lake</a>, and <a target="_blank" href="https://mlflow.org/">MlFlow</a> [10]. It unifies data warehousing and data lakes to provide an open and unified platform for data and AI. The <a target="_blank" href="https://www.databricks.com/product/data-lakehouse">Databricks Lakehouse</a> architecture is designed to manage all data types and is cloud-agnostic, allowing data to be governed wherever it is stored. Teams can collaborate and access all the data they need to innovate and improve. The platform includes the reliability and performance of <a target="_blank" href="https://www.databricks.com/product/delta-lake-on-databricks">Delta Lake</a> as the data lake foundation, fine-grained governance and support for persona-based use cases. It also provides instant and serverless compute, managed by Databricks. The Lakehouse platform eliminates the challenges caused by traditional data environments such as data silos and complicated data structures. It is simple, open, multi-cloud, and supports various data team workloads. The platform allows for flexibility with existing infrastructure, open source projects, and the <a target="_blank" href="https://www.databricks.com/company/partners">Databricks partner network</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xmy4g6tt2syqazgmcld.png" alt="Databricks (Source: databricks.com)" class="image--center mx-auto" /></p>
<p><strong>2)</strong> <a target="_blank" href="https://www.snowflake.com/en/"><strong>Snowflake</strong></a></p>
<p>Snowflake is a cloud data platform offering a software-as-a-service model fo storing and analyzing LARGE amounts of data. It is designed to support high levels of concurrency, scalability and performance. It allows customers to focus on getting value from their data rather than managing the infrastructure on which it's stored. The company was founded in 2012 by three experts, <a target="_blank" href="https://www.linkedin.com/in/benoit-dageville-3011845">Benoit Dashville</a>, <a target="_blank" href="https://www.linkedin.com/in/thierry-cruanes-3927363">Thierry Cruanes</a>, and <a target="_blank" href="https://www.crunchbase.com/person/marcin-zukowski">Marcin Zukowski</a> [11]. Snowflake runs on top of cloud infrastructure, such as AWS, Microsoft Azure, and Google's cloud platforms. It allows customers to store and analyze their data using the elasticity of the cloud, providing speed, ease of use, cost-effectiveness, and scalability. It is widely used for data warehousing, data lakes, and data engineering. It is designed to handle the complexities of modern data management processes. Not only that, but it also supports various data analytics applications, such as BI tools, ML/AI, and data science. Snowflake also revolutionized the pricing model by utilizing a "<strong>utilization model</strong>" that focuses on a client's consumption based on whether they're computing or storing data, making everything more flexible and elastic.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kf74iic3naorn55gfsnf.png" alt="Snowflake (Source: snowflake.com)‌‌" /></p>
<p>Key features of Snowflake include:</p>
<ul>
<li><p><strong>Scalability:</strong> Snowflake offers scalability through its multi-cluster shared data architecture, allowing for easy scaling up and down of resources as needed.</p>
</li>
<li><p><strong>Cloud-Agnostic:</strong> Snowflake is available on all major cloud providers (AWS, GCP, AZURE) while maintaining the same user experience, allowing for easy integration with current cloud architecture.</p>
</li>
<li><p><strong>Auto-scaling + Auto-Suspend:</strong> Snowflake automatically starts and stops clusters during resource-intensive processing and stops virtual warehouses when idle for cost and performance optimization.</p>
</li>
<li><p><strong>Concurrency and Workload Separation:</strong> Snowflake's multi-cluster architecture separates workloads to eliminate concurrency issues and ensures that queries from one virtual warehouse will not affect another.</p>
</li>
<li><p><strong>Zero Hardware + Software config:</strong> Snowflake does not require software installation or hardware config or commissioning, making it easy to set up and manage.</p>
</li>
<li><p><strong>Semi-Structured Data:</strong> Snowflake's architecture allows for the storage of structured and semi-structured data through the use of VARIANT data types.</p>
</li>
<li><p><strong>Security:</strong> Snowflake offers a wide range of security features, including network policies, authentication methods and access controls, to ensure secure data access and storage.</p>
</li>
</ul>
<p><strong>4)</strong> <a target="_blank" href="https://cloud.google.com/bigquery"><strong>Google Bigquery</strong></a></p>
<p><a target="_blank" href="https://cloud.google.com/bigquery">Google BigQuery</a> is a fully-managed and serverless data warehouse provided by Google Cloud that helps organizations manage and analyze large amounts of data with built-in features such as machine learning, geospatial analysis, and business intelligence[12]. It allows businesses and organizations to easily store, ingest, store, analyze, and visualize large amounts of data. Bigquery is designed to handle up to petabyte-scale data and supports SQL queries for data analysis purposes. The platform also includes BigQuery ML, which allows businesses or users to train and execute machine learning models using their enterprise data without needing to move it around.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ek08ctlnbo8h7be297u5.png" alt="BigQuery (Source: cloud.google.com/bigquery)" /></p>
<p>BigQuery integrates with various business intelligence tools and can be easily accessed through the cloud console, a command-line tool, and even APIs. It is also directly integrated with <a target="_blank" href="https://cloud.google.com/iam">Google Cloud’s Identity and Access Management Service</a> so that one can securely share data and analytics insights across organizations. With BigQuery, businesses only have to pay for data storing, querying, and streaming inserts. Loading and exporting data are absolutely free of charge.</p>
<p><strong>3)</strong> <a target="_blank" href="https://aws.amazon.com/redshift/"><strong>Amazon Redshift</strong></a></p>
<p><a target="_blank" href="https://aws.amazon.com/redshift/">Amazon Redshift</a> is a cloud-based data warehouse service that allows for the storage and analysis of large data sets. It is also useful for migrating LARGE databases. The service is fully managed and offers scalability and cost-effectiveness for storing and analyzing large amounts of data. It utilizes SQL to analyze structured and semi-structured data from a variety of sources, including data warehouses, operational databases, and data lakes, which are enabled by AWS-designed hardware and powered by AI &amp; machine learning; due to this, it is able to deliver optimal cost-performance at any scale. The service also offers high-speed performance and efficient querying capabilities to assist in making business decisions.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmdbuw2isva22my63hnr.png" alt="Amazon Redshift (Source: Amazon Redshift)" class="image--center mx-auto" /></p>
<p><strong>Key features of Amazon Redshift include:</strong></p>
<ul>
<li><p><strong>High Scalability</strong>: Redshift allows users to start with a very small amount of data and scale up to a petabyte or more as their data grows incrementally.</p>
</li>
<li><p><strong>Query execution + Performance</strong>: Redshift uses <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/dg/c_columnar_storage_disk_mem_mgmnt.html">columnar storage</a>, <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/dg/c_challenges_achieving_high_performance_queries.html#data-compression">advanced compression</a>, and <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/dg/c_challenges_achieving_high_performance_queries.html#massively-parallel-processing">parallel query execution</a> to deliver fast query performance on large data sets.</p>
</li>
<li><p><strong>Pay-as-you-go pricing mode</strong>l: Redshift uses a <a target="_blank" href="https://aws.amazon.com/redshift/pricing/?nc=sn&amp;loc=3">pay-as-you-go pricing model</a> and allows users to choose from a range of node types and sizes to optimize cost and performance.</p>
</li>
<li><p><strong>Robust Security</strong>: Redshift integrates with AWS security services like <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-authentication-access-control.html">AWS Identity and Access Management</a> (IAM) and <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-security-groups.html">Amazon Virtual Private Cloud (VPC)</a>—and more(learn more from <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/mgmt/iam-redshift-user-mgmt.html">here</a>)—to keep data safe.</p>
</li>
<li><p><strong>Integration</strong>: Redshift can be easily integrated with varios other services such as <a target="_blank" href="https://www.datacoral.com/aws-partnership/">Datacoral</a>, <a target="_blank" href="https://etleap.com/partners/aws-amazon-web-services/">Etleap</a>, <a target="_blank" href="https://fivetran.com/partners/aws">Fivetran</a>, <a target="_blank" href="https://www.snaplogic.com/partners/amazon-web-services">SnapLogic</a>,<a target="_blank" href="https://www.stitchdata.com/data-warehouses/amazon-redshift/">Stitch</a>,<a target="_blank" href="https://www.upsolver.com/integrations/redshift">Upsolver</a>,<a target="_blank" href="https://www.matillion.com/technology/cloud-data-warehouse/amazon-redshift/">Matillion</a>—and more.</p>
</li>
<li><p><strong>Monitoring + Management tools</strong>: Redshift has various management and monitoring tools, including the <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html">Redshift Management Console</a> and <a target="_blank" href="https://docs.aws.amazon.com/redshift/latest/mgmt/metrics.html">Redshift Query Performance Insights</a>, to help users manage and monitor their clusters in their data warehouse.</p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>As the amount of data continues to grow at an unprecedented rate, the need for efficient data management and observability solutions has never been greater. But simply collecting and storing data won't cut it—it's the insights and value it can provide that truly matter. However, this can only be achieved if the data is high quality, up-to-date, and easily accessible. This is exactly where DataOps comes in—providing a powerful set of best practices and tools to improve collaboration, integration, and automation, allowing businesses to streamline their data pipelines, reduce costs and workload, and enhance data quality. Hence, by utilizing the tools mentioned above, businesses can minimize data-related expenses and extract maximum value from their data.</p>
<p>Don't let your data go to waste—harness its power with DataOps.</p>
<h2 id="heading-references"><strong>References</strong></h2>
<p>[1]. A. Dyck, R. Penners and H. Lichter, "Towards Definitions for Release Engineering and DevOps," 2015 IEEE/ACM 3rd International Workshop on Release Engineering, Florence, Italy, 2015, pp. 3-3, doi: 10.1109/RELENG.2015.10.</p>
<p>[2] Doyle, Kerry. “DataOps vs. MLOps: Streamline your data operations.” TechTarget, 15 February 2022, <a target="_blank" href="https://www.techtarget.com/searchitoperations/tip/DataOps-vs-MLOps-Streamline-your-data-operations">https://www.techtarget.com/searchitoperations/tip/DataOps-vs-MLOps-Streamline-your-data-operations</a>. Accessed 12 January 2023.</p>
<p>[3] Danise, Amy, and Bruce Rogers. “Fivetran Innovates Data Integration Tools Market.” Forbes, 11 January 2022, <a target="_blank" href="https://www.forbes.com/sites/brucerogers/2022/01/11/fivetran-innovates-data-integration-tools-market/">https://www.forbes.com/sites/brucerogers/2022/01/11/fivetran-innovates-data-integration-tools-market/</a>. Accessed 13 January 2023.</p>
<p>[4] Basu, Kirit. “What Is StreamSets? Data Engineering for DataOps.” <em>StreamSets</em>, 5 October 2015, <a target="_blank" href="https://streamsets.com/blog/what-is-streamsets/">https://streamsets.com/blog/what-is-streamsets/</a>. Accessed 13 January 2023.</p>
<p>[5] Chand, Swatee. “What is Talend | Introduction to Talend ETL Tool.” <em>Edureka</em>, 29 November 2021, <a target="_blank" href="https://www.edureka.co/blog/what-is-talend-tool/#WhatIsTalend">https://www.edureka.co/blog/what-is-talend-tool/#WhatIsTalend</a>. Accessed 12 January 2023.</p>
<p>[6] “Delivering real-time data products to accelerate digital business [white paper].” <em>K2View</em>, <a target="_blank" href="https://www.k2view.com/hubfs/K2View%20Overview%202022.pdf">https://www.k2view.com/hubfs/K2View%20Overview%202022.pdf</a>. Accessed 13 January 2023.</p>
<p>[7] “Complete introduction to Alteryx.” GeeksforGeeks, 3 June 2022, <a target="_blank" href="https://www.geeksforgeeks.org/complete-introduction-to-alteryx/">https://www.geeksforgeeks.org/complete-introduction-to-alteryx/</a>. Accessed 13 January 2023.</p>
<p>[8] “Apache Airflow: Use Cases, Architecture, and Best Practices.” Run:AI, <a target="_blank" href="https://www.run.ai/guides/machine-learning-operations/apache-airflow">https://www.run.ai/guides/machine-learning-operations/apache-airflow</a>. Accessed 12 January 2023.</p>
<p>[9] “What is AWS Glue? - AWS Glue.” AWS Documentation, <a target="_blank" href="https://docs.aws.amazon.com/glue/latest/dg/what-is-glue.html">https://docs.aws.amazon.com/glue/latest/dg/what-is-glue.html</a>. Accessed 13 January 2023.</p>
<p>[10] “About Databricks, founded by the original creators of Apache Spark™.” Databricks, <a target="_blank" href="https://www.databricks.com/company/about-us">https://www.databricks.com/company/about-us</a>. Accessed 18 January 2023.</p>
<p>[11] “You're never too old to excel: How Snowflake thrives with 'dinosaur' cofounders and a 60-year-old CEO.” LinkedIn, 4 September 2019, <a target="_blank" href="https://www.linkedin.com/pulse/youre-never-too-old-excel-how-snowflake-thrives-dinosaur-anders/">https://www.linkedin.com/pulse/youre-never-too-old-excel-how-snowflake-thrives-dinosaur-anders/</a>. Accessed 18 January 2023.</p>
<p>[12] “What is BigQuery?” <em>Google Cloud</em>, <a target="_blank" href="https://cloud.google.com/bigquery/docs/introduction">https://cloud.google.com/bigquery/docs/introduction</a>. Accessed 18 January 2023.</p>
]]></content:encoded></item><item><title><![CDATA[DataOps 101: An Introduction to the Essential Approach of Data Management Operations and Observability]]></title><description><![CDATA[In today's day and age, data has become a crucial asset for organizations across all kinds of industries. Industry after industry—from retail to e-commerce to manufacturing to accounting to insurance to healthcare to finance—uses data to fuel innovat...]]></description><link>https://pramitmarattha.com.np/dataops-101-an-introduction-to-the-essential-approach-of-data-management-operations-and-observability</link><guid isPermaLink="true">https://pramitmarattha.com.np/dataops-101-an-introduction-to-the-essential-approach-of-data-management-operations-and-observability</guid><category><![CDATA[data]]></category><category><![CDATA[dataops]]></category><category><![CDATA[Devops]]></category><category><![CDATA[observability]]></category><category><![CDATA[beginner]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Mon, 23 Jan 2023 05:36:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674449636325/16df9490-0465-4cf9-af0c-523fd09d66bb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's day and age, <a target="_blank" href="https://en.wikipedia.org/wiki/Data">data</a> has become a crucial asset for organizations across all kinds of industries. Industry after industry—from <a target="_blank" href="https://www.shopify.com/blog/what-is-retail">retail</a> to <a target="_blank" href="https://sell.amazon.com/learn/what-is-ecommerce">e-commerce</a> to <a target="_blank" href="https://www.shopify.com/blog/what-is-manufacturing-definition">manufacturing</a> to <a target="_blank" href="https://www.britannica.com/topic/accounting/The-balance-sheet">accounting</a> to <a target="_blank" href="https://www.maxlifeinsurance.com/blog/term-insurance/what-is-insurance">insurance</a> to healthcare to finance—uses data to fuel innovation, enhance operations, and make informed decisions. However, managing and utilizing data effectively is no easy task. That is exactly where the field of “<strong>DataOps</strong>” comes in. DataOps borrows concepts from <a target="_blank" href="https://aws.amazon.com/devops/what-is-devops/"><em>DevOps</em></a> and attempts to help organizations rapidly deliver the right data at a very fast pace. The traditional process for delivering data to the business can be really very slow and really time-consuming; therefore, DataOps aims to promote agility, flexibility, and the continuous delivery of fresh data.</p>
<p>In this article, we'll provide a comprehensive introduction and guide to <strong>DataOps</strong>, covering its essential key components, the benefits it offers, how it differs from <a target="_blank" href="https://aws.amazon.com/devops/what-is-devops/"><em>DevOps</em></a> and the best practices for implementing it. We'll also go over some of the potential challenges in implementing DataOps and provide resources for further reading on this vital data management operations strategy.</p>
<p>But first, let's define DataOps and explain why it's become such a crucial part of modern data management.</p>
<h2 id="heading-what-is-dataops"><strong>What is DataOps?</strong></h2>
<p>Data Operations, or DataOps for short, is used to describe a set of practices and processes that are designed to improve the collaboration, integration, and automation of data management operations and tasks [1]. These practices and processes include a focus on <a target="_blank" href="https://www.atlassian.com/agile">agile methodologies</a>. It is intended to help organizations better manage their data pipelines, reduce the workload and time required to develop and deploy new data-driven applications and improve the quality of the data being used. DataOps is meant to eliminate barriers between data engineers, data scientists and data/business analysts—as well as other teams and departments within an organization—enabling them to work together more efficiently and effectively to manage and analyze data.</p>
<p>Many businesses and organizations have already adopted DataOps principles to make better use of their data and increase productivity [2]. Let's take a look at "<a target="_blank" href="https://www.netflix.com/">Netflix</a>" as an example; they have a large and very complex data environment, with data coming from multiple different sources, including <a target="_blank" href="https://www.statista.com/statistics/250934/quarterly-number-of-netflix-streaming-subscribers-worldwide/">subscriber accounts</a>, <a target="_blank" href="https://help.netflix.com/en/node/101917">viewing or streaming activity</a>, and <a target="_blank" href="https://help.netflix.com/en/contactus">customer support inquiries</a>. To manage this data effectively, Netflix has implemented DataOps practices and tools, such as automation, collaboration, and monitoring. Netflix has automated the data ingestion, automation and preparation processes, allowing it to quickly and accurately integrate data from multiple different sources and prepare it for analysis, which will help Netflix directly gain a better understanding of subscriber activity, behaviour and preferences, which in turn allows it to make better decisions about content/movie/show recommendations, their own marketing campaigns, and product development.</p>
<h2 id="heading-why-is-dataops-important"><strong>Why is DataOps important?</strong></h2>
<p>In today's fast-paced modern business world, DataOps plays a vital role in helping businesses and organizations stay ahead, as the ability to analyze data rapidly and precisely can provide them with a competitive advantage over others. DataOps simplifies and automates the complex process of collecting, storing, and analyzing data, making it more efficient, accurate, and relevant to the business's needs/requirements. This enables businesses to make better use of their data assets and derive more value from them. Overall, DataOps plays a key part in any organization's data management and data management operations strategy because it lets them use their fresh data assets to drive business growth and fresh new innovations.</p>
<p>DataOps empowers businesses and organizations to make better, faster decisions and get the most out of their data. It helps them extract valuable insights—and drive productivity as a result. With the <a target="_blank" href="https://satoricyber.com/dataops/all-you-need-to-know-about-dataops-tools/">right tools</a> and a well-thought-out plan, (businesses) can make more informed timely decisions.[3] Nevertheless, a significant obstacle to data-driven initiatives is ensuring decision-makers have access to important data and know how to use it effectively[4]. DataOps helps bridge this gap and fosters collaboration between teams, thereby enabling organizations to deliver products faster and more effectively.</p>
<p>DataOps is a people-driven practice, meaning that it depends on the abilities and knowledge of the individuals. It is not a tool or application that can be bought and implemented without the required human resources. Instead, it necessitates a team of proficient data experts that can collaborate effectively and efficiently [7].</p>
<h2 id="heading-exploring-the-key-differences-between-devops-and-dataops"><strong>Exploring the Key Differences Between <em>DevOps</em> and <em>DataOps</em></strong></h2>
<p>DevOps is a set of practices that combines software development (Dev) and IT operations (Ops) to reduce system and application development lifecycles. DevOps has been defined as an organizational approach aimed at creating empathy and cross-functional collaboration [5]. It aims to establish an environment in which software development, building, testing, and release can occur more quickly, frequently, and consistently.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhv33dc2saz4n54dpcas.png" alt="What is DevOps? (Source: gitlab.com)
" class="image--center mx-auto" /></p>
<p>The main goal of <strong>DevOps</strong> is to improve the collaboration and communication between developers and operations teams and automate the build, test, and release service cycle and manage and monitor infrastructure and applications in production.</p>
<h3 id="heading-devops-lifecycle"><strong>DevOps Lifecycle</strong></h3>
<p>DevOps lifecycle consists of several phases that are followed when developing and maintaining software applications.</p>
<ul>
<li><p><strong><em>Plan</em></strong>: The <em>plan</em> phase involves identifying the goals/objectives of the project and the resources that will be required to complete it.</p>
</li>
<li><p><strong><em>Develop</em></strong>: Develop phase where the software is actually developed. This involves writing code, building mockups/prototypes, and testing the software to ensure it is functional.</p>
</li>
<li><p><strong><em>Test</em></strong>: The <em>test</em> phase comes after the software has been developed; it must be tested to ensure it is error-free and will function as intended. This may include unit testing, integration testing—and <a target="_blank" href="https://www.geeksforgeeks.org/general-steps-of-software-testing-process/">other types of testing</a>.</p>
</li>
<li><p><strong><em>Deploy</em></strong>: <em>Deploy</em> phase is where the software or application is deployed to a production environment where end users can use it.</p>
</li>
<li><p><strong><em>Maintain</em></strong>: <em>Maintain</em> phase is where the software will be maintained to guarantee it continues to work as expected. This could involve patch fixes, security upgrades and hotfixes to ensure the software runs smoothly indefinitely.</p>
</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/980hx6qqucqtblnwvfvw.png" alt="DevOps Lifecycle" class="image--center mx-auto" /></p>
<h3 id="heading-dataops-lifecycle"><strong>DataOps Lifecycle</strong></h3>
<p>The DataOps lifecycle typically consists of the following stages:</p>
<ul>
<li><p><strong>Ingest</strong>: <em>Ingest</em> stage involves extracting data from multiple different raw data sources and storing it in a centralized location, such as a <a target="_blank" href="https://aws.amazon.com/data-warehouse/">data warehouse</a> or <a target="_blank" href="https://aws.amazon.com/big-data/datalakes-and-analytics/what-is-a-data-lake/">data lake</a>.</p>
</li>
<li><p><strong>Prepare</strong>: Prepare stage is where data engineers and data scientists prepare the data for analysis by extracting, cleaning, and transforming it. This may involve tasks such as <a target="_blank" href="https://learn.microsoft.com/en-us/windows-server/storage/data-deduplication/overview">data deduplication</a>, <a target="_blank" href="https://www.geeksforgeeks.org/data-integration-in-data-mining/">data integration/mining</a> and <a target="_blank" href="https://towardsdatascience.com/what-is-feature-engineering-importance-tools-and-techniques-for-machine-learning-2080b0269f10">feature extraction</a>.</p>
</li>
<li><p><strong>Model</strong>: The model **stage involves building <a target="_blank" href="https://www.intel.com/content/www/us/en/analytics/data-modeling.html">AI/ML models</a> and other <a target="_blank" href="https://en.wikipedia.org/wiki/Statistical_model">statistical models</a> to analyze and make predictions based on the data. Data scientists are typically responsible for this stage.</p>
</li>
<li><p><strong>Visualize</strong>: Visualize stage involves creating charts, graphs and other visualizations to help others understand and interpret the data.</p>
</li>
<li><p><strong>Deploy</strong>: <em>Deploy</em> stage is where the models and other data products developed in previous stages are deployed and made available to end users.</p>
</li>
<li><p><strong>Observability</strong>: The observability stage involves monitoring and analyzing the performance of the data quality and ensuring that it meets the needs of the end users. This stage also involves collecting feedback and implementing improvements as needed.</p>
</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipv8lrolys5rr2c505ji.png" alt="DataOps Lifecycle" class="image--center mx-auto" /></p>
<p>To sum up, now that you know what sets the DataOps and DevOps lifecycles apart, DataOps seeks to optimize an organization's whole data lifecycle, from data ingestion and preparation through analysis and visualization. In contrast, DevOps is focused on enhancing the agility of the software development process through automation and integration. DataOps aims to improve the efficiency and effectiveness of data processing and utilization. It can be thought of as the function within an organization that controls the data journey from source to value[6].</p>
<h2 id="heading-collaboration-across-teams-for-data-delivery"><strong>Collaboration Across Teams for Data Delivery</strong></h2>
<p>DataOps is a collaborative effort within an organization, with many different teams of people working together to ensure that DataOps functions properly and delivers data value <a target="_blank" href="https://docs.google.com/document/d/12vrGjMNtoz6Vg7rQLRNbZd3dRcV2FnrIXJtgqFIHeGI/edit#bookmark=id.dq4mt4cvxxge">[3]</a>. So, before the data is delivered to end users, it is subjected to a number of treatments and refinements from multiple teams. Data scientists first use their data science techniques, such as machine learning and deep learning to build models using software stacks such as <a target="_blank" href="https://www.python.org/">Python</a> or <a target="_blank" href="https://www.r-project.org/">R</a> and tools such as <a target="_blank" href="https://spark.apache.org/">Spark</a> or <a target="_blank" href="https://www.tensorflow.org/">Tensorflow</a>, among others, and the models are then transferred to data engineers, who collect and manage the data used to train and evaluate these models, while data developers and data architects create complete applications that include the models. The data governance team then implements data access controls for training and benchmarking purposes, while the operations team ( "Ops") is in charge of putting everything together and making it available to end users.</p>
<h2 id="heading-key-components-of-dataops"><strong>Key Components of DataOps</strong></h2>
<p>DataOps involves several key components which work together to improve data management processes. These includes:</p>
<h3 id="heading-continuous-integration-and-continuous-delivery-cicd"><strong>Continuous integration and Continuous delivery (CI/CD)</strong></h3>
<p><a target="_blank" href="https://www.redhat.com/en/topics/devops/what-is-ci-cd">Continuous integration and Continuous delivery (CI/CD)</a> is a practice that involves frequently integrating and testing code changes and then quickly and efficiently pushing those changes to production environments. In DataOps, CI/CD plays a crucial role in ensuring the accuracy and consistency of data as it is integrated and delivered to the appropriate people/systems. By constantly developing, building, automating and testing data changes and then quickly delivering them to production without any downtime, DataOps teams can minimize the risk of errors and ensure that data is delivered in a timely and reliable manner.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vo1suc0bjtswh6tkzhih.png" alt="Continuous Integration and Continuous Delivery(CI/CD)‌‌" class="image--center mx-auto" /></p>
<h3 id="heading-data-governance"><strong>Data governance</strong></h3>
<p>The process of establishing policies, procedures, and standards for managing data assets, as well as an organizational structure to support enterprise data management, is known as data governance. Data governance in DataOps helps to ensure that data is collected, stored and used in a consistent and in ethical manner.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnshnzs1lcwxx9hyypeb.png" alt="Data Governance (Source: graymatteranalytics.com)
" class="image--center mx-auto" /></p>
<h3 id="heading-data-quality-management-and-measurement"><strong>Data quality management and measurement</strong></h3>
<p>Data quality management and measurement involve identifying, correcting, and preventing any errors or inconsistencies in data. It helps ensure that the data being used is fully reliable—and accurate. This is critical because poor data quality can lead to incorrect or misleading insights and decisions, which can have serious consequences.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ng8v56tecd8xetx09e6q.png" alt="Data Quality Measurement (Source: passionned.com)
" /></p>
<h3 id="heading-data-orchestration"><strong>Data Orchestration</strong></h3>
<p>Data orchestration refers to the management and coordination of data processing tasks in a data pipeline. It involves specifying and scheduling how tasks will be completed, as well as dealing with errors and how tasks interact with one another. Data orchestration is critical in DataOps for automating and optimizing the flow of data through the pipeline. This can include tasks such as extracting data from various sources, transforming and cleaning the data, and loading it into a target system for analysis or reporting purposes.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16v7x2d189xgknb8cbp7.png" alt="Data Orchestration" class="image--center mx-auto" /></p>
<h3 id="heading-dataops-observability"><strong>DataOps Observability</strong></h3>
<p>As we’ve already discussed what DataOps is, let’s briefly review it. DataOps is a collection of best practices and technology used to manage and develop data products, optimize data management processes, improve quality, speed, and collaboration and promote continuous improvement. DataOps is based on the same principles and practices as DevOps. Still, it has taken longer to become fully matured because data is constantly changing and can be more fragile than software applications/infrastructures. For example, let's suppose that if a software application goes down, it can be easily restored without significant impact, but if data becomes corrupted, it may have serious consequences. This is the exact reason why DataOps has taken longer to get off the ground compared to DevOps.</p>
<p>To ensure that data performs optimally and meets desired standards for quality, reliability, and efficiency, it is important to implement DataOps observability. This involves regularly observing and monitoring data and using the insights gained to make informed decisions. DataOps observability is a newer concept, but the practice of observability itself has a long history in the DevOps world. For example, observability platforms/solutions such as  <a target="_blank" href="https://www.appdynamics.com/">AppDynamics</a> and <a target="_blank" href="https://www.splunk.com/">Splunk</a> help software engineers improve application reliability and reduce site/app downtime.</p>
<p>DataOps observability is not just limited to testing and monitoring data quality and the data pipeline. It also includes monitoring the health of the <strong>machine learning models</strong>, analyzing the application security measures to data infrastructure, tracking <strong>KPI</strong> and <strong>business</strong> monitoring. In other words, it covers a wide range of areas beyond just monitoring the health of data quality and data pipeline.</p>
<p>DataOps observability is a somewhat ambiguous concept that is interpreted differently in the data community. Still, in essence, it refers to an organization's/businesses’ ability to fully understand the health of the data. To sum it up, DataOps observability must address a few key areas: data quality and data pipeline reliability. Data quality is important to business users who want high-quality data they can trust. Data pipeline reliability is critical to data engineers and scientists, who need their data pipeline to run smoothly. Also, In addition to these two components, DataOps observability includes BizOps, which tracks/monitors the health and <strong>KPI</strong> of the <strong>business</strong>, as well as monitors the usage and the cost of the data. This is exactly where <a target="_blank" href="https://www.chaosgenius.io/">Chaos Genius</a> fits in. Offering a complete <strong>observability</strong> solution, it facilitates businesses and organizations in testing the resilience and reliability of data, which can directly help businesses to improve their spending and boost their performance.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbbxvyacio03arnd4i61.png" alt="Chaos Genius" class="image--center mx-auto" /></p>
<p>To create a successful data product, businesses should focus on three key areas: <strong>data governance</strong>, <strong>data access and security</strong>, and <strong>DataOps and quality</strong>.</p>
<p>Data governance involves understanding where the data comes from, while data access and security ensure that the data is being used in an appropriate and secure manner. Finally, DataOps and Quality involve automation, orchestration, CI/CD, configuration management and observability to ensure that the data product is high quality. The unification of these use cases is essential for the success of the data product.</p>
<p>In a nutshell, "<strong>DataOps Observability</strong>" refers to the ability to monitor and understand the various processes and systems involved in data management, with the main goal of ensuring the reliability, trustworthiness, and business value of the data. It involves monitoring and analyzing data pipelines, ensuring the quality of the data and demonstrating the business value of the data through metrics like financial and operational efficiency. DataOps observability allows businesses to improve the efficiency of their data management processes and make better use of their data assets. It helps to ensure that data is accurate, reliable, and easily accessible, enabling businesses and organizations to make data-driven decisions and drive business value.</p>
<h2 id="heading-implementing-dataops"><strong>Implementing DataOps</strong></h2>
<p>Implementing DataOps involves following a number of steps to ensure that data is collected, stored, and used in a way that supports business goals/objectives. This starts by identifying the data requirements and specifying the sources and types of data needed. A data governance framework is then established to ensure that data is collected, stored and used in a consistent and compliant manner. Data pipelines are designed and implemented to extract, transform, and load data from various sources into a centralized repository, and data quality checks and monitoring are put in place to ensure the accuracy, completeness and consistency of the data. To support a data-driven culture, it is crucial to build a collaborative and cross-functional team and establish a focus on data literacy, continuous improvement, and data-driven decision-making. Finally, it is important to continuously monitor and optimize the DataOps processes to improve efficiency, effectiveness, and agility.</p>
<h2 id="heading-list-of-top-dataops-tools-and-platforms-available"><strong>List of Top DataOps tools and platforms available</strong></h2>
<p>One of the key components of DataOps is the use of specialized tools to manage and automate the flow of data. Tools can help with tasks such as scheduling and monitoring the execution of data pipelines, extracting, transforming and cleaning data, and integrating data from multiple different sources. There are various different DataOps tools available on the market, and the best choice will depend on your specific needs/requirements. Some tools are designed for general-purpose data integration and transformation, while others are more specialized for specific types of data or use cases. Here are some of the <em>TOP Trending and Popular</em> DataOps tools currently available on the market.</p>
<h3 id="heading-apache-airflow"><strong>Apache Airflow:</strong></h3>
<p><a target="_blank" href="https://airflow.apache.org/docs/apache-airflow/stable/">Apache airflow</a> is an open-source tool that is used for scheduling, monitoring and managing the execution of data pipelines. It provides a simple, intuitive interface for defining and organizing tasks, and it can be extended with custom plugins to support a wide range of data sources and destinations.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhyfsxw43litusxlegaq.png" alt="Apache Airflow(Source: airflow.apache.org)" class="image--center mx-auto" /></p>
<h3 id="heading-databricks"><strong>Databricks</strong></h3>
<p><a target="_blank" href="https://www.databricks.com/">Databricks</a> is a cloud-based platform for data engineering, data science and AI/ML. It is built on top of the <a target="_blank" href="https://spark.apache.org/">Apache Spark</a> big data processing engine and offers a variety of tools for working with large amounts of data. Databricks' collaborative workspace is a great way for groups to collaborate on data projects together in real time. It provides a fully web-based notebook-like environment for writing and executing code, as well as data exploration and visualization tools. Databricks consist of connectors for common data sources and destinations, a library of pre-built transformations and functions, and support for different programming languages.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yluk40ik5motewxsn5cn.png" alt="Databricks(Source: databricks.com)" class="image--center mx-auto" /></p>
<h3 id="heading-snowflake"><strong>Snowflake</strong></h3>
<p>Snowflake is not a DataOps tool per se, it's a platform that can be used as a foundation for DataOps. Snowflake is a cloud-based data storage and analytics platform that is widely used for data warehousing, data lakes and data engineering. It is designed to handle the complexities of modern data management processes, such as data integration, data quality, data security, and data governance and to support a variety of data analytics applications, such as BI tools, ML and data science.  Snowflake can also be used to manage the flow of data from various sources to the data warehouse, where it can be transformed, cleansed and optimized accordingly for analysis purposes. Snowflake’s architecture is designed to support high levels of concurrency, scalability and performance, making it well-suited for handling large amounts of data in real time. It also provides a number of features that supports data governance and security, such as data lineage, masking and auditing, which can be a very important consideration in DataOps environments.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/az43efq16e208ypqji6h.png" alt="Snowflake (Source: Snowflake.com)‌‌" class="image--center mx-auto" /></p>
<h3 id="heading-fivetran"><strong>Fivetran</strong></h3>
<p><a target="_blank" href="https://www.fivetran.com/">Fivetran</a> is also a cloud-based service that simplifies the process of transferring data between various sources and destinations(including <a target="_blank" href="https://www.snowflake.com/en/">Snowflake</a>). It includes a range of connectors for popular data sources and destinations, including databases, cloud storage, SaaS applications—and more. One of the main features of Fivetran is its ability to support real-time synchronization and incremental updates, which means that it can continuously transfer new and updated data. This makes it ideal for use in scenarios where data needs to be kept up-to-date in near real-time. Fivetran has the ability to transfer data, but it also has a number of tools for managing and monitoring data pipelines. These tools include a web-based dashboard for tracking the status of data transfers and alerts for detecting issues and fixing 'em.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51hyobkqcserhmhu2wwf.png" alt="Fivetran (Source: Fivetran.com)" /></p>
<h3 id="heading-talend"><strong>Talend</strong></h3>
<p>Talend is a commercial data integration platform that offers a wide range of tools for extracting, transforming, and loading (<a target="_blank" href="https://www.chaosgenius.io/blog/data-engineering-and-dataops-beginners-guide-to-building-data-solutions-and-solving-real-world-challenges/">ETL</a>) data. It includes an awesome and highly interactive graphical user interface (GUI) for building data pipelines and a library of pre-built connectors and transformations that can be used to integrate data from a wide range of sources and destinations. One of the main key features of Talend is its support for a wide range of data sources and destinations, including databases, cloud storage, SaaS applications—and more. It also includes support for <a target="_blank" href="https://medium.com/javarevisited/5-best-programming-language-for-software-development-and-data-engineering-f8d81e1fc7ad">popular programming languages</a>, which allows users to write custom transformations and integrations. Talend also provides a range of tools for data governance, data quality, and data management, including support for tracking and managing <a target="_blank" href="https://www.ibm.com/topics/data-lineage">data lineage</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5129kfag1ekg297uwkr.png" alt="Talend(Source: Talend.com)" class="image--center mx-auto" /></p>
<p>Learn more about the <a target="_blank" href="https://www.chaosgenius.io/blog/best-dataops-tools-optimize-data-management-observability-2023/">Top DataOps tools</a> available on the market in 2023.</p>
<h2 id="heading-future-of-dataops"><strong>Future of DataOps</strong></h2>
<p>DataOps is constantly evolving in response to emerging technologies and changing business needs. According to a report by <a target="_blank" href="https://market.biz/report/global-dataops-platform-market-gm/#DataOps_Platform_Market_Overview">MarketBiz</a>, the global DataOps platform market is expected to experience significant growth over the forecast period of 2023 - 2032, with a projected value of <em>$7,091.38</em> million. This growth is driven by the increasing demand for real-time data insights, the adoption of cloud-based solutions and the rising popularity of Agile and DevOps-related practices. The DataOps platform market is also anticipated to see growth in various regions, including <em>North America</em>, <em>Europe</em>, <em>Asia</em> <em>Pacific</em>, <em>Latin America</em>, the <em>Middle East</em>—and <em>Africa</em>. The market is projected to reach a value of $7,091.38 million, up from $1,150 million in 2022, with a compound annual growth rate of 22.4%.</p>
<p>The future of DataOps looks VERY bright with the current adoption of automation and artificial intelligence (AI). Automating data-related tasks and using AI/ML to analyze data allows businesses to reduce the time and resources needed for data management, leading to more efficient and accurate analysis. Another main key factor that will contribute to the future success of DataOps is the growing importance of data governance. As organizations collect and use more data, it is crucial to have proper controls in place to ensure data privacy/security. DataOps practices can help businesses establish and maintain effective data governance.</p>
<p>Overall, the future of DataOps is expected to see continued growth and evolution as businesses and organizations seek to optimize and leverage data-driven insights to drive their success.</p>
<h2 id="heading-dataops-in-action"><strong>DataOps in Action!</strong></h2>
<p>Previously, we discussed how Netflix uses DataOps to streamline its data management operations. To have a complete understanding of how DataOps is used in practice, let's examine a second case study. Suppose a leading online store/retailer decides to use DataOps to enhance their sales forecasting procedure. Previously, the retailer had difficulty making accurate sales forecasts due to the complexity of their data environment and the rigorous manual and laborious processes they had to go through to prepare and analyze data. To address these challenges, they formed a DataOps team that included data engineers, data scientists, and data/business analysts.</p>
<p>The team then implemented an automated data ingestion and transformation pipeline utilizing a market-leading <a target="_blank" href="https://www.softwaretestinghelp.com/tools/26-best-data-integration-tools/">data integration platform</a>. This allowed them to swiftly and efficiently gather sales data from multiple sources, including online transactions, in-store purchases, user product preferences, user activity, and market research. The data was then cleaned, transformed, and validated using a series of predefined rules and procedures to ensure that it was ready for final analysis. The team then collaborated with data scientists to create and deploy AI/ML models that could predict future sales trends. These models were trained on historical product sales data and were designed to learn and adapt over time, becoming more accurate as more data was supplied to them. And after that, the team worked with data/business analysts to integrate the sales forecasting technique into the retailer's overall decision-making processes. This included making dashboards and reports that showed the outputs of the forecasting models and how they worked, as well as integrating the forecasts into the retailer's systems for managing product inventory and setting up product prices.</p>
<p>The results of the DataOps implementation were impressive. The store was able to track sales more accurately, which significantly improved managing the product inventory and aided in making smarter business decisions.  Overall, the DataOps approach helped the retailer/store to make better understand and act on the data they had, leading to improved efficiency, accuracy, and agility.</p>
<h2 id="heading-resources-for-learning-more-about-dataops"><strong>Resources for learning more about DataOps</strong></h2>
<p>To learn more about DataOps, there are a number of resources available, including books, articles, online courses, videos and events/podcasts. Some recommendations(personal preference) includes:</p>
<p><strong>Books</strong>:</p>
<ul>
<li><p>“<strong>Creating a Data-Driven Enterprise with DataOps</strong>” by <strong>Ashish Thusoo</strong> and <strong>Joydeep Sen Sarma</strong></p>
</li>
<li><p>"<strong><em>Practical DataOps: Delivering Agile Data Science at Scale</em></strong>" by <strong>Harvinder Atwal</strong></p>
</li>
<li><p>“<strong>Data Teams: A Unified Management Model for Successful Data-Focused Teams</strong>” by <strong>Jesse Anderson</strong></p>
</li>
<li><p><strong>“Managing Data in Motion Data Integration Best Practice Techniques and Technologies” by April Reeve</strong></p>
</li>
<li><p>“<strong>The DataOps Cookbook</strong>” by <strong>Christopher Bergh</strong></p>
</li>
</ul>
<p><strong>Articles</strong>:</p>
<p>There are many articles available online that different cover aspects of DataOps.</p>
<ul>
<li><p><a target="_blank" href="https://www.johnsnowlabs.com/data-quality-as-a-crucial-part-of-dataops/">Data Quality as a Crucial Part of DataOps</a></p>
</li>
<li><p><a target="_blank" href="https://towardsdatascience.com/a-deep-dive-into-data-quality-c1d1ee576046">A Deep Dive Into Data Quality</a></p>
</li>
<li><p><a target="_blank" href="https://www.progress.com/docs/default-source/default-document-library/Progress/Documents/book-club/Managing-Data-in-Motion.p">Managing Data in Motion</a></p>
</li>
<li><p><a target="_blank" href="https://blogs.oracle.com/ai-and-datascience/post/what-is-dataops-everything-you-need-to-know">What is DataOps? Everything You Need to Know</a></p>
</li>
<li><p><a target="_blank" href="https://www.nexla.com/define-dataops/">What is DataOps?</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/data-ops/dataops-is-not-just-devops-for-data-6e03083157b7">DataOps is NOT Just DevOps for Data</a></p>
</li>
<li><p><a target="_blank" href="https://devops.com/dataops-devops-plus-big-data/">DataOps: DevOps Plus Big Data</a></p>
</li>
</ul>
<p><strong>Videos</strong>: There are several videos, online courses, and training courses available for those interested in learning more about DataOps.</p>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=0YCsS213YNA&amp;ab_channel=Qlik">What is DataOps?</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=HX6R55T_9ws&amp;ab_channel=UnravelData">DataOps 101 - Why, What, How?</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=osulZZkhZjI&amp;t=2s&amp;ab_channel=BigDataThoughts">What is DataOps?</a></p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>DataOps is a crucial approach to data management operations that enables businesses to improve the speed, quality, and reliability of data processing and analysis. It facilitates collaboration and communication and accelerates the delivery of insights and results at a rapid pace. While implementing DataOps can present challenges, following best practices and communicating the benefits to stakeholders can help ensure a successful adoption. As emerging technologies continue to change the industry, we may anticipate DataOps to evolve and potentially expand into more fields. Above all, DataOps is a people-driven discipline, meaning that it depends on the abilities and knowledge of the individuals. It is not a tool or application that can be bought and implemented without the required human resources. Instead, it necessitates a team of proficient data experts that can collaborate effectively and efficiently.</p>
<h2 id="heading-references"><strong>References</strong></h2>
<p>[1] Swanson, Brittany-Marie. “What is DataOps? Everything You Need to Know.” <em>Oracle Blogs</em>, 12 March 2018, <a target="_blank" href="https://blogs.oracle.com/ai-and-datascience/post/what-is-dataops-everything-you-need-to-know">https://blogs.oracle.com/ai-and-datascience/post/what-is-dataops-everything-you-need-to-know</a>. Accessed 7 January 2023.</p>
<p>[2] DataOps and the future of data management.” <em>MIT Technology Review</em>, 24 September 2019, <a target="_blank" href="https://www.technologyreview.com/2019/09/24/132897/dataops-and-the-future-of-data-management/">https://www.technologyreview.com/2019/09/24/132897/dataops-and-the-future-of-data-management/</a>. Accessed 6 January 2023.</p>
<p>[3] Valentine, Crystal, and William Merchan. “DataOps: An Agile Methodology for Data-Driven Organizations.” <em>Oracle</em>, <a target="_blank" href="https://www.oracle.com/a/ocom/docs/oracle-ds-data-ops-map-r.pdf">https://www.oracle.com/a/ocom/docs/oracle-ds-data-ops-map-r.pdf</a>. Accessed 6 January 2023.</p>
<p>[4] Anderson, C. (2019). Creating a Data-Driven Enterprise with DataOps. O'Reilly Media, Inc. Retrieved from <a target="_blank" href="https://www.oreilly.com/library/view/creating-a-data-driven/9781492049227/">https://www.oreilly.com/library/view/creating-a-data-driven/9781492049227/</a> Accessed 6 January 2023.</p>
<p>[5] A. Dyck, R. Penners and H. Lichter, "Towards Definitions for Release Engineering and DevOps," 2015 IEEE/ACM 3rd International Workshop on Release Engineering.</p>
<p>[6] Saurabh, Saket. “What is DataOps? | Platform for the Machine Learning Age.” Nexla, <a target="_blank" href="https://www.nexla.com/define-dataops">https://www.nexla.com/define-dataops</a>/. Accessed 7 January 2023.</p>
<p>[7] Heudecker, Nick. “Hyping DataOps - Nick Heudecker.” Gartner Blog Network, 31 July 2018, <a target="_blank" href="https://blogs.gartner.com/nick-heudecker/hyping-dataops/">https://blogs.gartner.com/nick-heudecker/hyping-dataops/</a>. Accessed 7 January 2023.</p>
]]></content:encoded></item><item><title><![CDATA[Data Engineering and DataOps: A Beginner's Guide to Building Data Solutions and Solving Real-World Challenges]]></title><description><![CDATA[Introduction
Data engineering is the process of designing, building, maintaining, and running systems and infrastructure for storing, processing, and analyzing large, complex datasets. It is a field that has recently become much more important becaus...]]></description><link>https://pramitmarattha.com.np/data-engineering-and-dataops-a-beginners-guide-to-building-data-solutions-and-solving-real-world-challenges</link><guid isPermaLink="true">https://pramitmarattha.com.np/data-engineering-and-dataops-a-beginners-guide-to-building-data-solutions-and-solving-real-world-challenges</guid><category><![CDATA[data]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[engineering]]></category><category><![CDATA[dataengineering]]></category><category><![CDATA[dataops]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Fri, 20 Jan 2023 05:48:38 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-introduction"><strong>Introduction</strong></h3>
<p>Data engineering is the process of designing, building, maintaining, and running systems and infrastructure for storing, processing, and analyzing large, complex datasets. It is a field that has recently become much more important because of the growth of “<a target="_blank" href="https://www.oracle.com/big-data/what-is-big-data/">big data</a>” and the growing reliance on business models that are driven by data. In fact, <a target="_blank" href="https://www.gensigma.com/blog/will-demand-for-data-engineers-fuel-a-talent-shortage-in-2021">according to a report by Gensigma</a>, demand for data engineers has grown so quickly that an organization needs at least 10 data engineers for every three data scientists. The global market for big data and data engineering services is also seeing significant growth, with estimates ranging from a whopping 18% to 31% increase on a per-year basis from 2017 to 2025. This shows how important it is to learn and improve data engineering skills since it can be a rewarding, high-paying, and in-demand field in the tech industry right now.</p>
<p>This particular innovation was primarily driven by the FAANG (now MAANGO) companies ( <a target="_blank" href="https://www.facebook.com/">Facebook</a> (Meta), <a target="_blank" href="https://www.amazon.com/">Amazon</a>, <a target="_blank" href="https://www.apple.com/">Apple</a>, <a target="_blank" href="https://www.netflix.com/">Netflix</a>, <a target="_blank" href="https://www.google.com/">Google</a>, and <a target="_blank" href="https://www.oracle.com/">Oracle</a> ), who have adopted data-driven business models and built advanced data infrastructure to support them. These companies have put a lot of money and time into hiring and developing data engineering talent and technologies. They have also helped create new tools and ways to manage and analyze data at a large scale.</p>
<p>So, nowadays, companies and businesses rely heavily on data to improve their products and services by understanding user actions and behavior. Because of this, they “<em>have to</em>” heavily rely on data engineers to design + build + maintain the infrastructure and systems that enable the collection, storage, and analysis of large and complex data sets. Data engineering has therefore become a crucial field, with skilled data engineers playing a key role in driving data-driven innovations. In this article, we’ll look into the different parts and processes involved in data engineering, including DataOps, and how they help companies and businesses use the power of data to make their products and services better.</p>
<h3 id="heading-collecting-and-storing-data"><strong>Collecting and Storing Data</strong></h3>
<p>In today’s digital world, virtually every online action you perform generates information that is collected and held onto by businesses, companies, or corporations. This includes visiting web apps and websites, ordering products or merchandise, using apps, and more. The MAIN question is, where do these companies keep all of this data? The answer is in a database management system (<a target="_blank" href="https://www.ibm.com/docs/en/zos-basic-skills?topic=zos-what-is-database-management-system">DBMS</a>).</p>
<p>There are two main types of DBMS:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fvt9w08wvqsjppu8c2q2.png" alt="Relational vs. Non-Relational DB (Source: https://towardsdatascience.com/relational-vs-non-relational-databases-f2ac792482e3)" /></p>
<p><strong>Relational databases</strong> Relational databases store data in a way that looks like a spreadsheet format, with rows + columns. These are often used to store structured data, such as customer orders/inventory. A few perfect examples of a relational databases are MySQL, PostgreSQL, <a target="_blank" href="https://mariadb.org/">MariaDB</a>, <a target="_blank" href="https://www.microsoft.com/en-us/sql-server/sql-server-downloads">Microsoft SQL Server</a>, and Oracle Database. To build a relational database, we need to make a “data model” that shows how the different tables work together. This helps to understand the entire picture and makes it easier to analyze the data which would make the analysis a great deal and a whole lott!! less complicated and difficult to do so.</p>
<p>**Non-relational databases (also referred to as NoSQL databases)**On the other hand, NoSQL (non-relational) databases store data in varied formats, like key-value pairs, documents, and graphs. It is often used for handling large amounts of unstructured or semi-structured data, such as that generated by social media + online giants. They are also well-suited for applications that require high levels of flexibility and scalability.</p>
<blockquote>
<p>The type of database a company uses depends on its specific needs. There are many different companies that make use of both relational and non-relational db to store and manage their data. For example, Amazon uses both relational and non-relational database(like cassandra + DynamoDB) to store customer, product catalog, and order, and ads info. Google also uses both types of databases, with relational databases (like MySQL) and non-relational databases (like Bigtable and Cloud Datastore). Facebook, Twitter, Netflix, Uber, Airbnb, LinkedIn, Indeed and Dropbox are also among the other companies that make use both relational and non-relational databases to store and manage their data. These databases are used to store and manage a wide variety of data, including user data, product and service data, and business-critical information.</p>
</blockquote>
<h3 id="heading-using-sql-to-communicate-with-databases"><strong>Using SQL to Communicate with Databases</strong></h3>
<p>We can make use of a scripting language like <a target="_blank" href="https://www.w3schools.com/sql/sql_intro.asp">Structured Query Language(SQL)</a> to extract all the necessary information from a database. SQL allows us to communicate with the database easily and helps to retrieve the desired data by passing very simple commands.</p>
<p>For example(as shown in the screenshot below), we can use commands like:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> table_name <span class="hljs-keyword">LIMIT</span> <span class="hljs-number">5</span>
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vahovhfdnhwo2exhqs86.png" alt="Try SQL editor (source: w3school)" /></p>
<p>This particular command retrieves the first five rows from a table(of 91 rows). SQL also allows us to perform various different kinds of operations, such as inserting, updating, and deleting data directly from the database itself. Learn more about SQL form <a target="_blank" href="https://www.tutorialspoint.com/sql/index.htm">here</a>.</p>
<h3 id="heading-using-programming-languages-with-databases"><strong>Using Programming Languages with Databases</strong></h3>
<p>In addition to Structured Query Language(SQL), we can also use a variety of different programming languages, such as <a target="_blank" href="https://www.python.org/">Python</a>, <a target="_blank" href="https://www.java.com/">Java</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">JavaScript</a>, <a target="_blank" href="https://www.r-project.org/">R</a>, <a target="_blank" href="https://julialang.org/">Julia</a>, <a target="_blank" href="https://www.scala-lang.org/">Scala,</a> or any other programming language as long as it supports a basic database connection and functions to perform all of those operations, to connect to databases and perform more advanced query operations on the data. This gives us greater flexibility and allows us to apply custom-created logic to the data.</p>
<h3 id="heading-the-data-engineering-process"><strong>The Data Engineering Process</strong></h3>
<p>Once the data is stored in a database, the next step is to use it to solve complex business problems. This can be achieved by creating dashboard metrics, machine learning models, and various other types of solutions. The process of going from raw data in a database to a final solution is known as “<strong>data engineering.</strong>” This “<strong>data engineering</strong>” process, also known as DataOps, usually may consist of several steps and can be different from company to company depending on its specific needs as well as requirements.</p>
<h3 id="heading-essential-role-of-oltp-and-olap-in-data-engineering"><strong>Essential Role of OLTP and OLAP in Data Engineering</strong></h3>
<p>Let’s skip ahead to the earlier section now that you understand what “<strong>data engineering</strong>” is.</p>
<p>Relational databases are designed for faster reading, writing, and updating of data, rather than in-depth analysis. This means that if you try to run a large analytics query on a relational database, it may not be able to handle the workload and could potentially crash. In order to gain insights from data, we need a different type of system that is optimized for analytics work. This is where OLAP (Online Analytical Processing) comes in. But wait!! So what is OLTP and OLAP??</p>
<p><strong>Online Transaction Processing (OLTP)</strong></p>
<p>Online Transaction Processing (OLTP) is a type of database system that is designed to support high-concurrency, data-intensive transactions. It is typically used to handle large volumes of data that are constantly being inserted + updated + deleted, such as in a retail or financial application. OLTP systems are typically implemented using a <strong>Relational Database Management System</strong> and use Structured Query Language (SQL) for data manipulation and query processing. Learn more from <a target="_blank" href="https://www.oracle.com/database/what-is-oltp/">here</a>.</p>
<p><strong>Online Analytical Processing (OLAP)</strong></p>
<p>On the other hand, Online Analytical Processing (OLAP) is a type of database system that is designed for fast querying and analysis of data. It is typically used to support business intelligence(BI) and decision-making activities, such as data mining, data analysis, statistical analysis, and reporting. OLAP systems are designed to support complex queries and calculations on large data sets, often involving aggregations and roll-ups of data across multiple dimensions. Learn more from <a target="_blank" href="https://www.ibm.com/topics/olap">here</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gybyfocxndbdbkeggxm.png" alt="OLTP vs OLAP" /></p>
<p><strong>Moving Data from OLTP to OLAP: ETL</strong></p>
<p>To analyze the data that is stored in an OLTP system, such as a <a target="_blank" href="https://www.postgresql.org/">Postgres</a> or <a target="_blank" href="https://www.mysql.com/">MySQL</a> database, we need to transfer it to an OLAP system or a Data Warehouse like <a target="_blank" href="https://www.snowflake.com/en/">Snowflake</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8em0h7gk97qqtme75ei1.png" alt="Snowflake" class="image--center mx-auto" /></p>
<p>This exact process is called ETL (extract, transform, load).</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/39y4jgt2t0c2wcvuj92j.png" alt="ETL" class="image--center mx-auto" /></p>
<p>ETL involves extracting data from one or multiple sources, transforming it based on business logic or the data warehouse design, and then loading it onto a one specific target location. Learn more about ETL from <a target="_blank" href="https://www.ibm.com/topics/etl">here</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ir48iys9gvfpbqtkdlk1.gif" alt="move from here to there" class="image--center mx-auto" /></p>
<h3 id="heading-traditional-and-modern-etl-approaches"><strong>Traditional and Modern “ETL” Approaches</strong></h3>
<p>Traditionally, ETL pipelines were developed through the laborious process of writing them from absolutely scratch. However, newer approaches and tools are constantly being developed, released, and made easily available for purchase on the market. So, for instance, rather than developing a complete ETL pipeline from scratch, you can use a platform and tools like <a target="_blank" href="https://aws.amazon.com/glue/"><strong>AWS Glue</strong></a> and <a target="_blank" href="https://www.fivetran.com/"><strong>Fivetran</strong></a> which provides a fully managed environment to Extract, load, and transform data in the data warehouse based on your specific requirements.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tildaryy6h8xkzx706x0.png" alt="Fivetran and AWS Glue" /></p>
<p>These particular tools are designed to save you the time and effort of having to manually write an entire ETL pipeline from absolute scratch. There are numerous tools available on the market, but it is important not to become TOO attached to any one of them because they may come and go. However, the fundamental concepts, such as understanding query languages and data processing systems like OLTP and OLAP, will remain the same forever.</p>
<h3 id="heading-the-data-processing-dilemma-batch-vs-real-time-processing"><strong>The Data Processing Dilemma: Batch vs. Real-Time Processing</strong></h3>
<p>Different businesses, companies, and people have different requirements. Some of them — those businesses and companies — want to view that data in real time, while others want to view their data only once (depending upon their use cases and requirements); Therefore, it is becoming increasingly important to carefully select the right processing system to manage and make use of that particular data. So in general, we have two processing techniques:</p>
<p><strong>1). Batch processing</strong></p>
<p><strong>2). Real-time processing</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3nk32x3wgofynq2jbn8.png" alt="Real-time vs. Batch processing (source: tibco.com)" /></p>
<p><strong>Batch processing</strong> involves persisting data as it comes in through events. For example, let's say A company named “<em>Awesome</em>” operates a simple e-commerce website that sells merchandise. The company uses batch processing to periodically extract data from its transactional DB and load it into a <a target="_blank" href="https://aws.amazon.com/data-warehouse/">data warehouse</a>. The data warehouse is used to perform data analysis and generate reports on customer behavior, sales, trends, and other business metrics; this is the perfect example of batch processing.</p>
<p>Whereas, <strong>Real-time processing</strong> involves persistently storing data as it comes in through events in real-time. For example, Companies like <a target="_blank" href="https://www.uber.com/">Uber</a> and <a target="_blank" href="https://indrive.com/en/home">In-Drive</a> use <a target="_blank" href="https://en.wikipedia.org/wiki/Global_Positioning_System">GPS</a> trackers in their fleets of vehicles. Every vehicle’s location, speed, and other data are constantly being sent to a centralized server by the GPS units installed in them. So, the real-time processing system set up by these companies analyzes the data from the GPS units in near real-time. This information is used to give passengers up-to-date updates on things like vehicle locations and expected arrival times.</p>
<h3 id="heading-processing-large-amounts-of-data"><strong>Processing Large Amounts of Data</strong></h3>
<p>For small amounts of data, it is possible to process it on a single computer. However, when dealing with HUGE amounts of data, multiple computers(processing powerhouse) are needed to divide and process the data in chunks and combine the final output.</p>
<p>There are several frameworks available for batch processing, such as <a target="_blank" href="https://hadoop.apache.org/">Hadoop</a>, <a target="_blank" href="https://storm.apache.org/">Apache Storm</a>, and <a target="_blank" href="https://dt-docs.readthedocs.io/en/stable/">DataTorrent RTS</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8jl8yk80bw66em0ilf3w.png" alt="Batch processing frameworks" class="image--center mx-auto" /></p>
<p>For <strong>real-time streaming</strong>, we have other frameworks and tools like <a target="_blank" href="https://kafka.apache.org/">Apache Kafka</a>, <a target="_blank" href="https://activemq.apache.org/">ActiveMQ</a>, and <a target="_blank" href="https://aws.amazon.com/kinesis/">AWS Kinesis</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n6dvp57y0e455gphccv6.png" alt="Real-time processing frameworks" class="image--center mx-auto" /></p>
<p>Choosing the right processing system depends on the specific needs and requirements. So, by understanding the difference between OLTP and OLAP and the options for batch and real-time processing, you can select the right tools and technology to build a solution that meets your exact requirements.</p>
<h3 id="heading-big-data-landscape-and-cloud-computing"><strong>Big data landscape and cloud computing</strong></h3>
<p>The big data landscape is filled with various tools/technology for multiple different types of work they do and issues they solve. However, processing large amounts of data requires a powerful system, such as big data-crunching machines like supercomputers. In the past, companies and businesses would build their own servers and maintain them in a local data center. This often resulted in multiple hardware failures and issues requiring maintenance and software upgrades.</p>
<h3 id="heading-benefits-of-moving-to-the-cloud"><strong>Benefits of Moving to the Cloud</strong></h3>
<p>Many businesses and companies are moving and transitioning their entire operations to the cloud to escape headaches associated with hardware breakdowns and regular software updates (<em>as we mentioned earlier</em>). Because of this, companies only have to pay for the resources that they really use, and they can scale their servers to meet any demand. Cloud service providers also provide several different kinds of services to manage large amounts of data and ease the process of storing and processing data, making the entire process much more manageable. According to a <a target="_blank" href="https://www.gartner.com/reviews/market/cloud-infrastructure-and-platform-services">Gartner cloud computing infrastructure ranking</a>, the top three cloud platform providers are <a target="_blank" href="https://aws.amazon.com/">Amazon Web Services (AWS)</a>, <a target="_blank" href="https://cloud.google.com/">Google Cloud Platform (GCP)</a>, and <a target="_blank" href="https://azure.microsoft.com/en-us/">Microsoft Azure</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yd7p4pf5pdcb9sxkd4qn.png" alt="Cloud Computing Platforms (source: educba.com)" /></p>
<p><strong>Modern Data Stack and Data Engineering Industry</strong></p>
<p>Once a business or company has its architecture running on a cloud platform and has established ETL pipelines and a data warehouse, they can use this data for analytics and machine learning applications. After that, data engineers + AI/ML engineers will be able to create and implement machine learning models in production, allowing the company to develop and obtain deep insights.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bo73g7o148nq059mjk24.png" alt="Photo by fabio on Unsplash" /></p>
<p><strong>Problems and Solutions in the Data Engineering Industry (The Emergence of the Modern Data Stack)</strong></p>
<p>The field of data engineering is growing rapidly and with it comes a wide range of MASSIVE challenges. One common issue is the difficulty of migrating data from local(on-premise) systems to cloud warehouses, which can get very complex and time-consuming. Many businesses encounter problems during this process and try to create solutions for them. When one company faces a problem, it is likely that other companies might encounter the same kind of issues and difficulties. This creates opportunities for companies/businesses to identify gaps in the market and develop new tools to address these needs. This is exactly what led to the development of the “<strong>Modern Data Stack</strong>”.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25nsdiqrzr9v6usxn62l.png" alt="Modern Data Stack (Source: lakefs.io)" class="image--center mx-auto" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qujx5fl4hohqus5k0d4i.gif" alt="Elmo" class="image--center mx-auto" /></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Data engineering is a very important field that plays a VITAL role in helping out businesses, companies, startups, and organizations break down valuable insights from the data they have. By mastering the skills of data gathering, storage, and analysis skills, data engineers can solve real-world business challenges and drive business growth by an order of magnitude!! Whether you’re just starting in data engineering or looking to advance your career, it’s important to continuously learn and improve your skills to stay competitive in this rapidly evolving field. You can become a top-performing engineer and make a meaningful contribution to the world if you have the correct tools, resources, and right mindset.</p>
]]></content:encoded></item><item><title><![CDATA[Docker vs. Container: Which Containerization Technology is Right for Your Project?]]></title><description><![CDATA[Introduction
The topic of containerization has become increasingly important in the world of software/IT industries. Two of the most popular technologies for containerization are Docker and Containerd. While both of these technologies offer similar f...]]></description><link>https://pramitmarattha.com.np/docker-vs-container-which-containerization-technology-is-right-for-your-project</link><guid isPermaLink="true">https://pramitmarattha.com.np/docker-vs-container-which-containerization-technology-is-right-for-your-project</guid><category><![CDATA[Docker]]></category><category><![CDATA[containers]]></category><category><![CDATA[container]]></category><category><![CDATA[technology]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Sun, 04 Dec 2022 17:41:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671134632255/CjcDh01Zcg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>The topic of <a target="_blank" href="https://www.ibm.com/cloud/learn/containerization">containerization</a> has become increasingly important in the world of software/IT industries. Two of the most popular technologies for containerization are <a target="_blank" href="https://www.docker.com/">Docker</a> and <a target="_blank" href="https://containerd.io/">Containerd</a>. While both of these technologies offer similar functionality, some key differences between them can make one better suited for your project than the other. In this article, we will explore the key differences between Docker and Containerd, and help you determine which containerization technology is right for your project.</p>
<h2 id="heading-what-is-containerization">What is Containerization?</h2>
<p>Before we dive into the differences between Docker and Containerd, it's essential to understand what containerization is and why it has become such a popular topic in the world of software and IT industries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671134627040/qzjunLbJy.png" alt="Containerization" /></p>
<p>In simple terms, containerization is the process of packaging an application and its dependencies into a lightweight and portable container. This container can then run on any infrastructure, whether on a local machine, in a cloud environment, or on a virtual machine.</p>
<blockquote>
<p>Containers are a way to package software in a format that can run consistently on any platform. This means that a developer can create an application on their personal local machine, test it on their local machine, and then run it on a remote server, all without any changes to the code. This makes it much easier to develop and deploy applications, since there is no need to worry about platform-specific differences.</p>
</blockquote>
<p>One of the key benefits of containerization is that it allows developers to create and deploy applications quickly and easily. Because the container includes everything the application needs to run, it can be deployed and run consistently on any infrastructure, without the need to worry about differences in <a target="_blank" href="url">operating systems</a> or other <a target="_blank" href="url">dependencies</a>. This makes it easier for developers to collaborate and share their work and for organizations to scale their applications quickly and efficiently.</p>
<h2 id="heading-what-is-docker">What is Docker?</h2>
<p>Docker is a fully open source containerization platform that enables developers to package and deploy their applications in a lightweight and portable manner. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671134628924/w2JPkejUt.png" alt="Docker" /></p>
<p>Docker uses containers to create a virtual environment containing all the dependencies and libraries required to run an application. This allows developers to build, test, and deploy their applications consistently and predictably, regardless of the underlying infrastructure.</p>
<p>One of the main benefits of using Docker is that it allows for more efficient use of resources on a host machine. Since each container is isolated from the others, multiple containers can run on the same host without interfering with each other. This means that a single host machine can run more applications, which can be helpful for organizations that need to run a large number of applications but may not have the resources to run them all on separate machines.</p>
<p>Docker also makes it easier to manage and scale applications. For example, if an application needs to be scaled up to handle more traffic, it is easy to spin up additional containers to handle the extra load. This can be done quickly and easily without the need to provision and configure new machines.</p>
<p>Another advantage of Docker is that it allows for easier collaboration between developers. Since containers contain all of the dependencies required to run an application, it is easy for developers to share their work with others. This means that developers can work on different parts of an application simultaneously without having to worry about conflicts or compatibility issues.</p>
<h2 id="heading-what-is-containerd">What is Containerd?</h2>
<p>Containerd also is a fully open source <a target="_blank" href="url">container runtime</a> designed to be used as a building block for other container platforms, including Docker. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1671134630951/gFUZHQYh7b.png" alt="Containerd" /></p>
<p>Containerd provides a low-level API that enables developers to create, manage, and distribute containers. Unlike Docker, which includes a full suite of tools and utilities for building, deploying, and managing containers, Containerd focuses on providing a simple and efficient container runtime.</p>
<p>At its core, containerd is a <a target="_blank" href="https://en.wikipedia.org/wiki/Daemon_(computing)">daemon</a> that runs on a host machine and manages the lifecycle of containers. It is responsible for managing the underlying processes that make up a container and providing an interface for other tools and services to interact with those containers. This allows developers and system administrators to easily manage and deploy containers without worrying about the low-level details of how containers work.</p>
<p>Another important aspect of containerd is its modular design. It comprises several different components, each of which performs a specific function within the container ecosystem. This modular design allows users to customize and extend containerd to suit their particular needs easily. It also makes it easy to integrate containerd into existing systems and workflows, allowing users to leverage the power of containers without having to make significant changes to their existing infrastructure.</p>
<p><strong>Key Differences Between Docker and Containerd:</strong></p>
<blockquote>
<p>Comparing containerd and Docker is like comparing a screwdriver to a toolbox. Both are essential, but they serve different purposes. While a screwdriver is a single tool used for a specific task, a toolbox holds various tools (including the screwdriver itself) that can be used for multiple tasks. Similarly, containerd is a single tool used for managing containers in a system, while Docker is a suite of tools that includes containerd and other tools for building, deploying, and running containers.</p>
</blockquote>
<ol>
<li><p>Architecture:
One of the key differences between Docker and Containerd is the architecture of the two technologies. Docker uses a client-server architecture, where the Docker daemon (or server) is responsible for managing the containers on a host machine, and the Docker CLI (or client) is used to communicate with the daemon. Containerd, on the other hand, uses a more modular architecture, where different components can be easily added or removed to create a custom container platform.</p>
</li>
<li><p>Scope of functionality:
Another critical difference between Docker and Containerd is the scope of functionality the two technologies provide. Docker includes a full suite of tools and utilities for building, deploying, and managing containers, including the <a target="_blank" href="https://docs.docker.com/engine/reference/commandline/cli/">Docker CLI</a>, <a target="_blank" href="https://docs.docker.com/compose/gettingstarted/">Docker Compose</a>, and <a target="_blank" href="https://vsupalov.com/what-is-docker-swarm/">Docker Swarm</a>. In contrast, Containerd is focused on providing a simple and efficient runtime for containers and does not include any additional tools or utilities.</p>
</li>
<li><p>Ease of use:
Docker and Containerd also differ in terms of their ease of use. Docker is designed to be user-friendly and easy to use, with a simple command-line interface and a wealth of documentation and tutorials available online. Containerd, on the other hand, is more geared towards experienced developers and may require a deeper understanding of containerization and runtime environments to use effectively.</p>
</li>
</ol>
<h2 id="heading-which-containerization-technology-is-right-for-your-project">Which Containerization Technology is Right for Your Project?</h2>
<p>The choice between Docker and Containerd ultimately depends on your project's specific requirements and goals. If you are looking for a complete container platform that is easy to use and provides a wide range of tools and utilities for building, deploying, and managing containers, then Docker may be the right choice. However, if you are looking for a more lightweight and modular container runtime that can be easily integrated into other container platforms, then Containerd may be a better option.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>After comparing Docker and Containerd, it can be concluded that the right containerization technology for a project depends on that project's specific needs and requirements. Both Docker and Containerd offer useful features and capabilities for managing and deploying containers, but they differ in some key areas. Docker provides a more comprehensive and user-friendly suite of tools for building, deploying, and managing containers, while Containerd provides a more lightweight and modular option with a focus on core container runtime functionality. Ultimately, the decision on which technology to use should be based on a thorough evaluation of the project's requirements and a consideration of the strengths and limitations of each option.</p>
]]></content:encoded></item><item><title><![CDATA[How to create SEO friendly documentation with DocZ?]]></title><description><![CDATA[Crafting documentation is difficult enough, but making it SEO friendly is a huge hurdle. In this article, I'll walk you through how to make documentation SEO friendly and what steps you need to take to get started from absolute scratch. This article ...]]></description><link>https://pramitmarattha.com.np/how-to-create-seo-friendly-documentation-with-docz</link><guid isPermaLink="true">https://pramitmarattha.com.np/how-to-create-seo-friendly-documentation-with-docz</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[SEO]]></category><category><![CDATA[SEO for Developers]]></category><category><![CDATA[documentation]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Thu, 12 May 2022 11:21:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1652354385232/sSBz5aw7_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Crafting documentation is difficult enough, but making it SEO friendly is a huge hurdle. In this article, I'll walk you through how to make documentation SEO friendly and what steps you need to take to get started from absolute scratch. This article assists you in certain ways in crafting your documentation and making it more SEO friendly, so read it carefully and thoroughly before implementing it.</p>
<h2 id="heading-what-is-seo">What is SEO?</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mu7q8wjyn0ics9tx19a0.png" alt="SEO" /></p>
<p>The technique of improving your website for search engines is known as search engine optimization (SEO). The primary goal of SEO optimization on any given webpage, web application, website, or documentation is to improve the quality of that content so that search engines will include it in their results, potentially increasing the number of visitors as well as traffics to that particular application.</p>
<h2 id="heading-how-does-it-work">How does it work?</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljl0vhfed8be7tmsxdnv.png" alt="Crawler" /></p>
<p>Let's look at how SEO works in practice now that we've learned about it. So there's something known as search engine crawlers(also known as bots) which crawl through all of the content available out there on the internet, and they do so by tracking and filtering internal links within websites as well as links between websites. The crawler reads the content on each page, including redirection links, URLs, tags, headings, and a slew of other elements, to gain a sense of what the site's content is all about, and then sends that information to the search engine provider, who creates an index out of it and then ranks the site based on it.</p>
<h2 id="heading-factors-that-impact-seo-rankings">Factors that impact SEO rankings</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s87hdz73xw775u86vf85.png" alt="SEO ranking" /></p>
<p>There are a plethora of factors that influence overall search engine rankings, for example, such as high-quality, authentic information/content, incoming links, or backlinking. These are the obvious things that might attract/lure a massive amount of user base to the content, but there are a few other important SEO factors that you might want to consider which are as follows:</p>
<ul>
<li>Keyword Usage</li>
<li>Backlinks</li>
<li>Quality Content</li>
<li>Speed</li>
<li>User Experience(UX)</li>
<li>HTML format</li>
<li>Domain authority</li>
<li>Social Media Links</li>
<li>Mobile Optimization</li>
</ul>
<p>These are the factors that, when paired with the search engine's understanding of your original material, will be used to convert an index into queries/rankings for various searches conducted within search engines.</p>
<p>Now that we've covered the fundamentals of SEO, let's get started building an SEO-rich documentation site with Docz. To do so, follow the procedures outlined below . But first, let's have a better understanding of what docz is.</p>
<h2 id="heading-what-is-docz">What is Docz?</h2>
<p>Producing documentation is a very daunting task. So, docz was built to remedy this problem. Docz makes use of GatsbyJS's incredible capabilities, allowing you to swiftly construct live-reloading, SEO-friendly, production-ready, fully customisable documentation pages in just a matter of minutes. To discover everything there is to know about Docz, follow the article mentioned below.</p>
<p>Before we get started with docz for the purposes of this tutorial, we'll be using the gatsby theme for our docz project, so, first and foremost, let's try to understand what actually is GatsbyJS.</p>
<h2 id="heading-what-is-gatsbyjs">What is GatsbyJS?</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w70cocetzg21jlfigwar.png" alt="Gatsby" /></p>
<p>Gatsby is a completely open-source framework that integrates the capabilities of <code>React</code>, <code>GraphQL</code>, and <code>Webpack</code> into a single tool for creating blazingly fast, super reliable, robust and flexible static webpages and applications.</p>
<blockquote>
<p>keep in mind that docz's core is based entirely on Gatsby.</p>
</blockquote>
<h2 id="heading-what-are-gatsby-themes">What are Gatsby Themes?</h2>
<p>Gatsby themes are plugins that include a <code>gatsby-config.js</code> file and allow Gatsby sites to have pre-configured functionality, data sourcing, and/or UI code. Gatsby themes can be thought of as distinct Gatsby sites that can be put together to help users to break up a larger Gatsby project!</p>
<h2 id="heading-docz-and-gatsby">Docz and Gatsby</h2>
<p>Use <code>gatsby-theme-docz</code> if you wish to use Docz in a Gatsby application. It's now easier than ever to get started constructing a Gatsby site, thanks to the inclusion of theming in Gatsby. As a Gatsby Theme, you can prepackage shared functionality, data sourcing, and design. Not only that, but the Docz theme includes all of the components and algorithms required to produce a documentation page, allowing users to explore and develop a truly useful documentation site.</p>
<h2 id="heading-setting-up-docz-with-gatsby-theme">Setting up Docz with Gatsby theme</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kak38p96cbkb4c9gsdiq.png" alt="Docz" /></p>
<p>To begin, you must first initialize npm in an empty directory, after which you can only install the packages listed below.</p>
<pre><code>npm <span class="hljs-keyword">init</span> -y
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixbz7beurd2pqxw6c9s8.png" alt="npm inititlaize" /></p>
<p>You can install it using yarn or npm.(For this tutorial I will using yarn)</p>
<pre><code><span class="hljs-built_in">npm</span> install gatsby gatsby-theme-docz@next docz@next react react-dom
</code></pre><p>or</p>
<pre><code><span class="hljs-attribute">yarn</span> add gatsby gatsby-theme-docz<span class="hljs-variable">@next</span> docz<span class="hljs-variable">@next</span> react react-dom
</code></pre><p>The project will take a few minutes to set up, so you can go grab a cup of coffee in the meanwhile.</p>
<pre><code>docz<span class="hljs-operator">-</span>seo<span class="hljs-operator">-</span>demo<span class="hljs-operator">&gt;</span> yarn add gatsby gatsby<span class="hljs-operator">-</span>theme<span class="hljs-operator">-</span>docz@next docz@next react react<span class="hljs-operator">-</span>dom
yarn add v1<span class="hljs-number">.22</span><span class="hljs-number">.4</span>
info No lockfile found.
[<span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">4</span>] Resolving packages...
[<span class="hljs-number">2</span><span class="hljs-operator">/</span><span class="hljs-number">4</span>] Fetching packages...
[<span class="hljs-number">3</span><span class="hljs-operator">/</span><span class="hljs-number">4</span>] Linking dependencies...
[<span class="hljs-number">4</span><span class="hljs-operator">/</span><span class="hljs-number">4</span>] Building packages...
...
...
...
├─ webpack@<span class="hljs-number">5.72</span><span class="hljs-number">.0</span>
├─ websocket<span class="hljs-operator">-</span>driver@<span class="hljs-number">0</span><span class="hljs-number">.7</span><span class="hljs-number">.4</span>
├─ websocket<span class="hljs-operator">-</span>extensions@<span class="hljs-number">0</span><span class="hljs-number">.1</span><span class="hljs-number">.4</span>
├─ whatwg<span class="hljs-operator">-</span>url@<span class="hljs-number">5.0</span><span class="hljs-number">.0</span>
├─ which<span class="hljs-operator">-</span>boxed<span class="hljs-operator">-</span>primitive@<span class="hljs-number">1.0</span><span class="hljs-number">.2</span>
├─ yargs<span class="hljs-operator">-</span>parser@<span class="hljs-number">18.1</span><span class="hljs-number">.3</span>
├─ yeast@<span class="hljs-number">0</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>
├─ yn@<span class="hljs-number">3.1</span><span class="hljs-number">.1</span>
└─ yocto<span class="hljs-operator">-</span>queue@<span class="hljs-number">0</span><span class="hljs-number">.1</span><span class="hljs-number">.0</span>
Done in <span class="hljs-number">573</span>.64s.
</code></pre><p>Your <code>package.json</code> file should look something like this after your dependencies have been successfully installed.</p>
<pre><code>{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"docz-seo-demo"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"docz"</span>: <span class="hljs-string">"1.0.3"</span>,
    <span class="hljs-attr">"docz-theme-default"</span>: <span class="hljs-string">"1.0.3"</span>,
    <span class="hljs-attr">"gatsby"</span>: <span class="hljs-string">"^2.3.23"</span>,
    <span class="hljs-attr">"gatsby-theme-docz"</span>: <span class="hljs-string">"1.0.3"</span>,
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"^16.8.6"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"^16.8.6"</span>,
  }
}
</code></pre><p>Now that the project is up and running, create a file called <code>gatsby-config.js</code> and add <code>gatsby-theme-docz</code> to the plugins section. After you've done that, your configuration should look like this.</p>
<pre><code><span class="hljs-comment">//gatsby-config.js</span>
module.exports <span class="hljs-operator">=</span> {
  plugins: [<span class="hljs-string">"gatsby-theme-docz"</span>],
};
</code></pre><p>Then, let's get to work on some documentation. To do so, simply create one mdx file and paste the following code into it.</p>
<pre><code><span class="hljs-meta">---</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Heelloooooo!</span>
<span class="hljs-attr">route:</span> <span class="hljs-string">/</span>
<span class="hljs-meta">---</span>

<span class="hljs-comment"># Hello thereee!</span>

<span class="hljs-string">Hello,</span> <span class="hljs-string">I</span> <span class="hljs-string">am</span> <span class="hljs-string">awesome!!</span>
</code></pre><p>Your file and folder structure should look something like this</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgzi6pywpr59qfnfep12.png" alt="Folder structure" /></p>
<p>Now just run gatsby in development mode:</p>
<pre><code><span class="hljs-attribute">yarn</span> gatsby develop
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/toctafoffpu5x1ksw646.png" alt="Gatsby Develop" /></p>
<p>It's time to make a <code>docz</code> configuration file, so make a file called <code>doczrc.js</code> and paste the following code into it.</p>
<pre><code> module.exports <span class="hljs-operator">=</span> {
  plugins: [
    {
      resolve: <span class="hljs-string">"gatsby-theme-docz"</span>,
    },
  ],
};
</code></pre><p>Use options inside the plugin definition to set some settings for your theme.</p>
<pre><code><span class="hljs-comment">//doczrc.js</span>
module.exports <span class="hljs-operator">=</span> {
  plugins: [
    {
      resolve: <span class="hljs-string">'gatsby-theme-docz'</span>,
      options: {
        <span class="hljs-comment">/* ADD your custom options */</span>
      },
    },
  ],
}
</code></pre><hr />
<h3 id="heading-lets-make-our-documentation-seo-friendly">Let's make our Documentation SEO friendly</h3>
<p>To make our documentation SEO-friendly, we must first include metadata, a favicon, and a description. To do so, follow the procedures given below.</p>
<p>Configuring Gatsby in conjunction with react-helmet-async is how you add metadata to your site. Keep in mind that we're talking about react-helmet-async, not react-helmet. Because react-helmet-async is an API-compatible clone, you should only need to import from a different package.</p>
<h3 id="heading-component-shadowing">Component shadowing</h3>
<p>Component Shadowing is a concept that Gatsby Themes introduces. This feature enables users to alter the rendering of a component by overriding it. Other theming systems make it impossible to change features of a theme if there isn't a built-in configuration option. Component Shadowing is a powerful escape hatch for users who want to make rapid, one-time modifications. If the component that you want to shadow has the matching folder structure and name the theme component will get automatically shadowed.</p>
<h3 id="heading-overriding-the-wrapper-component">Overriding the wrapper component</h3>
<p>The metadata is configured in a file called wrapper.js in the gatsby-theme-docz docz theme package. To override it, we must Shadow the component, which means we must create a copy of the file in our own source directory with the same file path and its name.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bop1pfrprokgq3q67mx4.png" alt="Folder structure" /></p>
<p>Now paste the following code into the wrapper.js file you just created. This component should be used as a wrapper instead of the main core theme component. So, this wrapper consists of all the necessary elements that are required to make the documentation SEO rich. </p>
<pre><code>// <span class="hljs-keyword">wrapper</span>.js
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { Helmet } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-helmet-async'</span>

const <span class="hljs-keyword">Wrapper</span> = ({ children, doc }) =&gt; &lt;React.Fragment&gt;
    &lt;Helmet&gt;
        &lt;meta charSet="utf-8" /&gt;
        &lt;title&gt;My Shadow!&lt;/title&gt;
        &lt;link rel="icon"
            <span class="hljs-keyword">type</span>="image/png"
              href="http://example.com/myicon.png"
        /&gt;
    &lt;/Helmet&gt;
    {children}
&lt;/React.Fragment&gt;
export <span class="hljs-keyword">default</span> <span class="hljs-keyword">Wrapper</span>
</code></pre><p>The next stage in making your documentation SEO friendly is to provide very specific descriptions, titles, and keywords, for example.</p>
<pre><code><span class="hljs-meta">---</span>
<span class="hljs-attr">title:</span> <span class="hljs-string">Very</span> <span class="hljs-string">detailed</span> <span class="hljs-string">title</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">Short</span> <span class="hljs-string">description</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">page</span>
<span class="hljs-attr">keywords:</span> [<span class="hljs-string">Perfect</span>, <span class="hljs-string">Matching</span>, <span class="hljs-string">Keywords</span>]
<span class="hljs-meta">---</span>
</code></pre><h2 id="heading-static-html-generation">Static HTML generation</h2>
<p>Docz with gatsby works as a static site generator, which means that HTML files are generated statically for each URL route, making it easier for search engines to find your material/content.</p>
<h2 id="heading-image-alt-description">Image alt description​</h2>
<p>When an image can't be seen visually, such as when using a screen reader or when the image fails t load, the alt tag tells the search engine what the image is all about. In Markdown, alt tags are also supported. You can also give your image a title, which has a huge impact on SEO but is displayed as a tooltip when hovering over it, and is typically used to provide info of that particular image.</p>
<pre><code>![<span class="hljs-string">This is an image of something</span>](<span class="hljs-link">./image/image.png</span>)
</code></pre><h2 id="heading-readable-links">Readable links​</h2>
<p>Docz creates links from your file names, but you may readily modify that using route according to your own desire.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp5p4nbk2v3xxgn7oi9o.png" alt="page-data" /></p>
<h2 id="heading-structured-content">Structured content​</h2>
<p>To understand the structure of your webpage, search engines rely on HTML code. When Docz displays your pages, semantic markup is utilized to divide the various portions of the page, assisting the search engine in locating parts and its different content.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>To summarize what we learned, we learnt about SEO, then we learned about docz, and we configured and implemented docz with a custom gatsby theme, and finally, we specified completely on the factors that affect the SEO of the documentation by applying and demonstrating by example.</p>
]]></content:encoded></item><item><title><![CDATA[Song search application built using Typesense.]]></title><description><![CDATA[Crafting search engines from absolute scratch which are typo-tolerant, effective, and efficient is really very difficult. A typographical error could cause a search to return nothing, even if the requested item is in the database. By obviating the ne...]]></description><link>https://pramitmarattha.com.np/song-search-application-built-using-typesense</link><guid isPermaLink="true">https://pramitmarattha.com.np/song-search-application-built-using-typesense</guid><category><![CDATA[THW Web Apps]]></category><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[search]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Sun, 01 May 2022 10:24:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1651400546324/JhT-gN0Dl.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Crafting search engines from absolute scratch which are typo-tolerant, effective, and efficient is really very difficult. A typographical error could cause a search to return nothing, even if the requested item is in the database. By obviating the need to develop a search engine, Typesense could save a lot of time and effort. Your users will also be able to use the search feature in your app effectively, resulting in a positive user experience. Typesense is an open-source typo-tolerant search engine for developers, designed to cut down on the time it takes to find information quickly. To learn more about typesense, go to the following link.</p>
<ul>
<li><a target="_blank" href="https://typesense.org/docs/overview/what-is-typesense.html">What is Typesense?</a></li>
</ul>
<p>This article will walk you through installing Typesense, creating a new application from scratch, preconfiguring the client, and more. This article will also show you how to construct a Typesense Collection. Finally, we’ll start our app and initialize it, then add an item to our collection and start searching.</p>
<h2 id="heading-building-a-song-search-application-from-scratch">Building a Song Search Application from scratch!</h2>
<h3 id="heading-typesense-configuration">Typesense Configuration</h3>
<p>Typesense can be used by installing its prebuilt docker image which is already provided to us by Typesense or by using the <a target="_blank" href="https://cloud.typesense.org/">Typesense cloud</a> hosting solution, which is the most straightforward way to get started. To get started, go to the Typesense cloud website and sign up with your Github account, or use the docker method easily and directly. We’ll use the Docker method for the purposes of this tutorial.To follow along with this tutorial, go to the <a target="_blank" href="https://hub.docker.com/r/typesense/typesense/">Typesense Dockerhub</a> and download the prebuilt docker image, then follow the instructions below.</p>
<pre><code><span class="hljs-attribute">docker</span> pull typesense/typesense
</code></pre><p>and</p>
<pre><code>mkdir <span class="hljs-operator">/</span>tmp<span class="hljs-operator">/</span>typesense<span class="hljs-operator">-</span>data
docker run <span class="hljs-operator">-</span>p <span class="hljs-number">8108</span>:<span class="hljs-number">8108</span> <span class="hljs-operator">-</span>v<span class="hljs-operator">/</span>tmp<span class="hljs-operator">/</span>data:<span class="hljs-operator">/</span>data typesense<span class="hljs-operator">/</span>typesense:<span class="hljs-number">0</span><span class="hljs-number">.22</span><span class="hljs-number">.2</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>data<span class="hljs-operator">-</span>dir <span class="hljs-operator">/</span>data <span class="hljs-operator">-</span><span class="hljs-operator">-</span>api<span class="hljs-operator">-</span>key<span class="hljs-operator">=</span>songsearch <span class="hljs-operator">-</span><span class="hljs-operator">-</span>enable<span class="hljs-operator">-</span>cors <span class="hljs-operator">-</span><span class="hljs-operator">-</span>listen<span class="hljs-operator">-</span>port <span class="hljs-number">8108</span>
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03mc7s6dgt2i0826etgs.png" alt="Docker run" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hq1pe90tbqx1s9a6r7w4.png" alt="Docker desktop" /></p>
<h3 id="heading-building-search-uis-from-scratch">Building Search UIs from scratch.</h3>
<p>Using the open source InstantSearch.js library library or its React, Vue, and Angularjs, as well as the Typesense-InstantSearch-Adapter, you can create a plug-and-play full-featured search interface with just a few lines of code.</p>
<p>Finally, lets’s actually build a search UI for our Application .</p>
<h3 id="heading-step-by-step-instructions-for-installing">Step-by-step instructions for installing</h3>
<p>Let’s begin with a basic template:</p>
<pre><code>npx create<span class="hljs-operator">-</span>instantsearch<span class="hljs-operator">-</span>app typesense<span class="hljs-operator">-</span>songsearch
</code></pre><pre><code>? <span class="hljs-selector-tag">The</span> <span class="hljs-selector-tag">name</span> <span class="hljs-selector-tag">of</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">application</span> <span class="hljs-selector-tag">or</span> <span class="hljs-selector-tag">widget</span> <span class="hljs-selector-tag">typesense-songsearch</span>
? <span class="hljs-selector-tag">InstantSearch</span> <span class="hljs-selector-tag">template</span> <span class="hljs-selector-tag">InstantSearch</span><span class="hljs-selector-class">.js</span>

<span class="hljs-selector-tag">Creating</span> <span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">new</span> <span class="hljs-selector-tag">InstantSearch</span> <span class="hljs-selector-tag">app</span> <span class="hljs-selector-tag">in</span> <span class="hljs-selector-tag">typesense-songsearch</span>.

? <span class="hljs-selector-tag">InstantSearch</span><span class="hljs-selector-class">.js</span> <span class="hljs-selector-tag">version</span> 4<span class="hljs-selector-class">.38</span><span class="hljs-selector-class">.0</span>
? <span class="hljs-selector-tag">Application</span> <span class="hljs-selector-tag">ID</span> <span class="hljs-selector-tag">latency</span>
? <span class="hljs-selector-tag">Search</span> <span class="hljs-selector-tag">API</span> <span class="hljs-selector-tag">key</span> 6<span class="hljs-selector-tag">be0576ff61c053d5f9a3225e2a90f76</span>
? <span class="hljs-selector-tag">Index</span> <span class="hljs-selector-tag">name</span> <span class="hljs-selector-tag">instant_search</span>
? <span class="hljs-selector-tag">Attributes</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">display</span>
  <span class="hljs-selector-tag">Used</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">generate</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">default</span> <span class="hljs-selector-tag">result</span> <span class="hljs-selector-tag">template</span>
? <span class="hljs-selector-tag">Attributes</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">display</span>
  <span class="hljs-selector-tag">Used</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">filter</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">search</span> <span class="hljs-selector-tag">interface</span> <span class="hljs-selector-tag">Dynamic</span> <span class="hljs-selector-tag">widgets</span>

📦  <span class="hljs-selector-tag">Installing</span> <span class="hljs-selector-tag">dependencies</span>...

<span class="hljs-selector-tag">yarn</span> <span class="hljs-selector-tag">install</span> <span class="hljs-selector-tag">v1</span><span class="hljs-selector-class">.22</span><span class="hljs-selector-class">.0</span>
<span class="hljs-selector-tag">info</span> <span class="hljs-selector-tag">No</span> <span class="hljs-selector-tag">lockfile</span> <span class="hljs-selector-tag">found</span>.
<span class="hljs-selector-attr">[1/4]</span> 🔍  <span class="hljs-selector-tag">Resolving</span> <span class="hljs-selector-tag">packages</span>...
<span class="hljs-selector-attr">[2/4]</span> 🚚  <span class="hljs-selector-tag">Fetching</span> <span class="hljs-selector-tag">packages</span>...
<span class="hljs-selector-attr">[3/4]</span> 🔗  <span class="hljs-selector-tag">Linking</span> <span class="hljs-selector-tag">dependencies</span>...
<span class="hljs-selector-attr">[4/4]</span> 🔨  <span class="hljs-selector-tag">Building</span> <span class="hljs-selector-tag">fresh</span> <span class="hljs-selector-tag">packages</span>...
<span class="hljs-selector-tag">success</span> <span class="hljs-selector-tag">Saved</span> <span class="hljs-selector-tag">lockfile</span>.

<span class="hljs-selector-tag">Done</span> <span class="hljs-selector-tag">in</span> 173<span class="hljs-selector-class">.57s</span>.

🎉  <span class="hljs-selector-tag">Created</span> <span class="hljs-selector-tag">typesense-songsearch</span> <span class="hljs-selector-tag">at</span> <span class="hljs-selector-tag">typesense-songsearch</span>.

<span class="hljs-selector-tag">Begin</span> <span class="hljs-selector-tag">by</span> <span class="hljs-selector-tag">typing</span>:

  <span class="hljs-selector-tag">cd</span> <span class="hljs-selector-tag">typesense-songsearch</span>
  <span class="hljs-selector-tag">yarn</span> <span class="hljs-selector-tag">start</span>

⚡️  <span class="hljs-selector-tag">Start</span> <span class="hljs-selector-tag">building</span> <span class="hljs-selector-tag">something</span> <span class="hljs-selector-tag">awesome</span>!
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3nui2zl5q01ownb6yr8.png" alt="Instantsearch app setup" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5sdntps1ijvbp9rwz75.png" alt="Instantsearch app setup" /></p>
<p>This is how your folder structure should look after you’ve finished installing your Instantsearch app (UI).</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxaa8ze7ajsb1u2rp85z.png" alt="Folder structure" /></p>
<p>For the <code>npx create-instantsearch-app</code> command, here are some setup suggestions: Any of the web libraries supported by typesense can be used, including <code>InstantSearch.js</code>, <code>React</code>, <code>Vue</code>, and <code>Angular</code>. The default version of <code>InstantSearch.js</code> can be used. The application ID can be any string; we’ll be changing it later in the article. Search API key: any string - later in the guide, we’ll replace this with the Typesense Search-only API Key and Our index name is the name of the collection in Typesense, and lastly , leave the Displaying attributes as it is.</p>
<p>Next, we’ll need to install the Typesense InstantSearch adapter to use InstantSearch with a Typesense backend:</p>
<pre><code>npm install typesense<span class="hljs-operator">-</span>instantsearch<span class="hljs-operator">-</span>adapter
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nebyy9na9hrvex6t2hqc.png" alt="typesense instantsearch adapter" /></p>
<h3 id="heading-installing-typesense">Installing Typesense</h3>
<pre><code><span class="hljs-built_in">npm</span> install typesense
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxzcb0q1t1qt7i09bir5.png" alt="Install typesense" /></p>
<p>We’re ready to create a Typesense collection, Now that everything is installed and running, we can create a Typesense collection, index some documents in it, and try searching for them.</p>
<p>Your <code>package.json</code> file should look like this after you’ve installed all of the necessary dependencies.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"typesense-songsearch"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"src/app.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"parcel index.html --port 3000"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"parcel build index.html"</span>,
    <span class="hljs-attr">"lint"</span>: <span class="hljs-string">"eslint ."</span>,
    <span class="hljs-attr">"lint:fix"</span>: <span class="hljs-string">"npm run lint -- --fix"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"babel-eslint"</span>: <span class="hljs-string">"10.0.3"</span>,
    <span class="hljs-attr">"eslint"</span>: <span class="hljs-string">"5.7.0"</span>,
    <span class="hljs-attr">"eslint-config-algolia"</span>: <span class="hljs-string">"13.2.3"</span>,
    <span class="hljs-attr">"eslint-config-prettier"</span>: <span class="hljs-string">"3.6.0"</span>,
    <span class="hljs-attr">"eslint-plugin-import"</span>: <span class="hljs-string">"2.19.1"</span>,
    <span class="hljs-attr">"eslint-plugin-prettier"</span>: <span class="hljs-string">"3.1.2"</span>,
    <span class="hljs-attr">"parcel-bundler"</span>: <span class="hljs-string">"1.12.5"</span>,
    <span class="hljs-attr">"prettier"</span>: <span class="hljs-string">"1.19.1"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"algoliasearch"</span>: <span class="hljs-string">"4"</span>,
    <span class="hljs-attr">"instantsearch.js"</span>: <span class="hljs-string">"4.38.0"</span>,
    <span class="hljs-attr">"typesense"</span>: <span class="hljs-string">"^0.14.0"</span>,
    <span class="hljs-attr">"typesense-instantsearch-adapter"</span>: <span class="hljs-string">"^2.2.0"</span>
  }
}
</code></pre>
<p>As you can see, it’s a very basic app with only two important files: <code>app.js</code> and <code>index.html</code>, which contains the structure of our entire app.</p>
<p>In the <code>index.html</code> file, you can see an id. We can use those ids to attach UI components such as a <code>searchbox</code>, <code>results</code>, and <code>facets</code> if you want to include them, as well as <code>pagination</code> widgets.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span>
      <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1, shrink-to-fit=no"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"#000000"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"manifest"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./manifest.webmanifest"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"shortcut icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./favicon.png"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/index.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/app.css"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-title"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-subtitle"</span>&gt;</span>
        using
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com/algolia/instantsearch.js"</span>&gt;</span>
          InstantSearch.js
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__filters"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dynamic-widgets"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__results"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchbox"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hits"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"pagination"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/algoliasearch@4.10.5/dist/algoliasearch-lite.umd.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.js@4.38.0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./src/app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>As you can see below, the <code>app.js</code> file is configured for algolia, and we’ll need to change that for typesense.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// app.js</span>
<span class="hljs-keyword">const</span> { algoliasearch, instantsearch } = <span class="hljs-built_in">window</span>;

<span class="hljs-keyword">const</span> searchClient = algoliasearch(<span class="hljs-string">"latency"</span>, <span class="hljs-string">"songsearch"</span>);

<span class="hljs-keyword">const</span> search = instantsearch({
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">"instant_search"</span>,
  searchClient,
});
search.addWidgets([
  instantsearch.widgets.searchBox({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#searchbox"</span>,
  }),
  instantsearch.widgets.hits({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#hits"</span>,
  }),
  instantsearch.widgets.configure({
    <span class="hljs-attr">facets</span>: [<span class="hljs-string">"*"</span>],
    <span class="hljs-attr">maxValuesPerFacet</span>: <span class="hljs-number">20</span>,
  }),
  instantsearch.widgets.dynamicWidgets({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#dynamic-widgets"</span>,
    fallbackWidget({ container, attribute }) {
      <span class="hljs-keyword">return</span> instantsearch.widgets.refinementList({
        container,
        attribute,
      });
    },
    <span class="hljs-attr">widgets</span>: [],
  }),
  instantsearch.widgets.pagination({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#pagination"</span>,
  }),
]);

search.start();
</code></pre>
<p>To use InstantSearch with a Typesense backend, we’ll need to install the Typesense InstantSearch adapter. To do so, simply open a terminal window and type the following command into it.</p>
<blockquote>
<p>If you’ve already installed it, you can skip this step.</p>
</blockquote>
<pre><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save typesense<span class="hljs-operator">-</span>instantsearch<span class="hljs-operator">-</span>adapter
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2gcokj4zgpcx902shn2.png" alt="Typesense adapter installation" /></p>
<p>Finally, the project can be adjusted to use Typesense. In the background, we’ve got our typesense instance up and running. Open src/app.js and change the way InstantSearch is initialized to get InstantSearch.js to use the Typesense adapter:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> searchClient = algoliasearch(<span class="hljs-string">"latency"</span>, <span class="hljs-string">"songsearch"</span>);

<span class="hljs-keyword">const</span> search = instantsearch({
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">"instant_search"</span>,
  searchClient,
});
</code></pre>
<p>to this</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"songsearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,primary_artist_name,album_name"</span>, <span class="hljs-comment">//quering by</span>
  },
});
<span class="hljs-keyword">const</span> searchClient = typesenseInstantsearchAdapter.searchClient;

<span class="hljs-keyword">const</span> search = instantsearch({
  searchClient,
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">"songs"</span>,
});
</code></pre>
<p>Now we need to import our songs data, so create a dataset folder and inside it, create your own songs json file, filling it with all of the necessary song information, or download the songs dataset from here. Finally, your folder structure should look something like this.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aelk0xig71ptjvmxvj6o.png" alt="Folder structure" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4thblmtycfuqfvaiqurx.png" alt="loaddata" /></p>
<p>Let’s get to work on the data-importing scripts. We’ll start by creating a file called <code>loadData.js</code> and we will export and initialize the typesense client inside but before we do that we need to install a few packages <code>lodash</code> and <code>fast-json-stringify</code>.</p>
<pre><code><span class="hljs-built_in">npm</span> i lodash
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qyv5doksyexg62kwmwr.png" alt="lodash" /></p>
<p>and</p>
<pre><code>npm i fast<span class="hljs-operator">-</span>json<span class="hljs-operator">-</span>stringify
</code></pre><p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/foxbz3vhkz9cvp7xls3t.png" alt="JSON Stringify" /></p>
<p>So, at the very top, import all of the dependencies that this script requires to run, as shown below.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> _ = <span class="hljs-built_in">require</span>(<span class="hljs-string">"lodash"</span>);
<span class="hljs-keyword">const</span> fastJson = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fast-json-stringify"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> readline = <span class="hljs-built_in">require</span>(<span class="hljs-string">"readline"</span>);
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);
</code></pre>
<p>After that, Create a stringify based on the schema of the documents that need to be stringified.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> _ = <span class="hljs-built_in">require</span>(<span class="hljs-string">"lodash"</span>);
<span class="hljs-keyword">const</span> fastJson = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fast-json-stringify"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> readline = <span class="hljs-built_in">require</span>(<span class="hljs-string">"readline"</span>);
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-keyword">const</span> stringify = fastJson({
  <span class="hljs-attr">title</span>: <span class="hljs-string">"Song Schema"</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
  <span class="hljs-attr">properties</span>: {
    <span class="hljs-attr">track_id</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">title</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">album_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      <span class="hljs-attr">nullable</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">primary_artist_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">genres</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      },
    },
    <span class="hljs-attr">country</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">release_date</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"integer"</span>,
    },
    <span class="hljs-attr">release_decade</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">release_group_types</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      },
    },
    <span class="hljs-attr">urls</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
        <span class="hljs-attr">properties</span>: {
          <span class="hljs-attr">type</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
          },
          <span class="hljs-attr">url</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
          },
        },
      },
    },
  },
});
</code></pre>
<p>Create a new <code>extractUrls</code> function.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">extractUrls</span>(<span class="hljs-params">parsedRecord</span>) </span>{
  <span class="hljs-keyword">return</span> parsedRecord[<span class="hljs-string">"relations"</span>]
    .filter(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span>
      [
        <span class="hljs-string">"amazon asin"</span>,
        <span class="hljs-string">"streaming"</span>,
        <span class="hljs-string">"free streaming"</span>,
        <span class="hljs-string">"download for free"</span>,
        <span class="hljs-string">"purchase for download"</span>,
      ].includes(r[<span class="hljs-string">"type"</span>])
    )
    .map(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">type</span>: r[<span class="hljs-string">"type"</span>], <span class="hljs-attr">url</span>: r[<span class="hljs-string">"url"</span>][<span class="hljs-string">"resource"</span>] };
    });
}
</code></pre>
<p>Now create an asynchronous <code>addSongsToTypesense</code> function and copy the code exactly as it is shown below. This function will simply index all of the songs into Typesense, and if an error occurs during the process, it will simply log an error.</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addSongsToTypesense</span>(<span class="hljs-params">songs, typesense, songsCollection</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> returnDataChunks = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
      _.chunk(songs, <span class="hljs-built_in">Math</span>.ceil(songs.length / CHUNK_SIZE)).map(<span class="hljs-function">(<span class="hljs-params">songsChunk</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> jsonlString = songsChunk
          .map(<span class="hljs-function">(<span class="hljs-params">song</span>) =&gt;</span> stringify(song))
          .join(<span class="hljs-string">"\n"</span>);

        <span class="hljs-keyword">return</span> typesense
          .collections(songsCollection)
          .documents()
          .import(jsonlString);
      })
    );

    <span class="hljs-keyword">const</span> failedItems = returnDataChunks
      .map(<span class="hljs-function">(<span class="hljs-params">returnData</span>) =&gt;</span>
        returnData
          .split(<span class="hljs-string">"\n"</span>)
          .map(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">JSON</span>.parse(r))
          .filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.success === <span class="hljs-literal">false</span>)
      )
      .flat();
    <span class="hljs-keyword">if</span> (failedItems.length &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(
        <span class="hljs-string">`Error indexing items <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(failedItems, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)}</span>`</span>
      );
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}
</code></pre>
<p>A Collection in Typesense is a set of related Documents that functions similarly to a table in a relational database. We give a collection a name and describe the fields that will be indexed when a document is added to the collection when we create it.</p>
<p>Now go to the <code>loadData.js</code> file and add the following changes to the code.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client({
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"songsearch"</span>,
  });

  <span class="hljs-keyword">const</span> songsCollection = <span class="hljs-string">"songs"</span>;
  <span class="hljs-keyword">const</span> schema = {
    <span class="hljs-attr">name</span>: songsCollection,
    <span class="hljs-attr">fields</span>: [
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"track_id"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"title"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"album_name"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"primary_artist_name"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"genres"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string[]"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"country"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_date"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"int64"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_decade"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_group_types"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string[]"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
    ],
    <span class="hljs-attr">default_sorting_field</span>: <span class="hljs-string">"release_date"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Populating data in Typesense "<span class="hljs-subst">${songsCollection}</span>" collection`</span>);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Creating schema...`</span>);
  <span class="hljs-keyword">await</span> typesense.collections().create(schema);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Songs records...`</span>);

  <span class="hljs-keyword">const</span> fileStream = fs.createReadStream(DATA_FILE);
  <span class="hljs-keyword">const</span> rl = readline.createInterface({
    <span class="hljs-attr">input</span>: fileStream,
    <span class="hljs-attr">crlfDelay</span>: <span class="hljs-literal">Infinity</span>,
  });

  <span class="hljs-keyword">let</span> songs = [];
  <span class="hljs-keyword">let</span> currentLine = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> line <span class="hljs-keyword">of</span> rl) {
    currentLine += <span class="hljs-number">1</span>;
    <span class="hljs-keyword">const</span> parsedRecord = <span class="hljs-built_in">JSON</span>.parse(line);
    <span class="hljs-keyword">try</span> {
      songs.push(
        ...parsedRecord[<span class="hljs-string">"media"</span>]
          .map(<span class="hljs-function">(<span class="hljs-params">media</span>) =&gt;</span> media[<span class="hljs-string">"tracks"</span>])
          .flat()
          .filter(<span class="hljs-function">(<span class="hljs-params">track</span>) =&gt;</span> track) <span class="hljs-comment">// To remove nulls</span>
          .map(<span class="hljs-function">(<span class="hljs-params">track</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> releaseDate =
              <span class="hljs-built_in">Math</span>.round(
                <span class="hljs-built_in">Date</span>.parse(
                  parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"first-release-date"</span>]
                ) / <span class="hljs-number">1000</span>
              ) || <span class="hljs-number">0</span>;

            <span class="hljs-comment">// Be sure to update the schema passed to stringify when updating this structure</span>
            <span class="hljs-keyword">const</span> song = {
              <span class="hljs-attr">track_id</span>: track[<span class="hljs-string">"id"</span>],
              <span class="hljs-attr">title</span>: track[<span class="hljs-string">"title"</span>],
              <span class="hljs-attr">album_name</span>: parsedRecord[<span class="hljs-string">"title"</span>],
              <span class="hljs-attr">primary_artist_name</span>:
                parsedRecord[<span class="hljs-string">"artist-credit"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"artist"</span>][<span class="hljs-string">"name"</span>],
              <span class="hljs-attr">genres</span>: [
                ...track[<span class="hljs-string">"recording"</span>][<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
                ...parsedRecord[<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
                ...parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
              ].map(
                <span class="hljs-function">(<span class="hljs-params">[firstChar, ...rest]</span>) =&gt;</span>
                  firstChar.toUpperCase() + rest.join(<span class="hljs-string">""</span>).toLowerCase()
              ),
              <span class="hljs-attr">country</span>: parsedRecord[<span class="hljs-string">"country"</span>] || <span class="hljs-string">"Unknown"</span>,
              <span class="hljs-attr">release_date</span>: releaseDate,
              <span class="hljs-attr">release_decade</span>: <span class="hljs-string">`<span class="hljs-subst">${
                <span class="hljs-built_in">Math</span>.round(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(releaseDate * <span class="hljs-number">1000</span>).getUTCFullYear() / <span class="hljs-number">10</span>) *
                <span class="hljs-number">10</span>
              }</span>s`</span>,
              <span class="hljs-attr">release_group_types</span>: [
                parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"primary-type"</span>] || <span class="hljs-string">"Unknown"</span>,
                parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"secondary-types"</span>] || <span class="hljs-literal">null</span>,
              ]
                .flat()
                .filter(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e),
              <span class="hljs-attr">urls</span>: extractUrls(parsedRecord),
            };
            process.stdout.write(<span class="hljs-string">"-"</span>);

            <span class="hljs-keyword">return</span> song;
          })
      );
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.error(e);
      <span class="hljs-built_in">console</span>.error(parsedRecord);
      <span class="hljs-keyword">throw</span> e;
    }

    <span class="hljs-keyword">if</span> (currentLine &gt;= MAX_LINES) {
      <span class="hljs-keyword">break</span>;
    }
  }

  <span class="hljs-keyword">if</span> (songs.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">await</span> addSongsToTypesense(songs, typesense, songsCollection);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ALL songs INDEXED ✅ !"</span>);
  }
})();
</code></pre>
<p>If an error occurs while loading the data, simply add the following snippet of code to the <code>loadData.js</code> file before creating <code>songSchema</code>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3cixue8xgg9yxrc4ify3.png" alt="loadData" /></p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"songs"</span>).delete();
</code></pre>
<p>This is how your final code should look like.</p>
<pre><code class="lang-js"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> _ = <span class="hljs-built_in">require</span>(<span class="hljs-string">"lodash"</span>);
<span class="hljs-keyword">const</span> fastJson = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fast-json-stringify"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> readline = <span class="hljs-built_in">require</span>(<span class="hljs-string">"readline"</span>);
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-keyword">const</span> stringify = fastJson({
  <span class="hljs-attr">title</span>: <span class="hljs-string">"Song Schema"</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
  <span class="hljs-attr">properties</span>: {
    <span class="hljs-attr">track_id</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">title</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">album_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      <span class="hljs-attr">nullable</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">primary_artist_name</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">genres</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      },
    },
    <span class="hljs-attr">country</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">release_date</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"integer"</span>,
    },
    <span class="hljs-attr">release_decade</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
    },
    <span class="hljs-attr">release_group_types</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
      },
    },
    <span class="hljs-attr">urls</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-string">"array"</span>,
      <span class="hljs-attr">items</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"object"</span>,
        <span class="hljs-attr">properties</span>: {
          <span class="hljs-attr">type</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
          },
          <span class="hljs-attr">url</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
          },
        },
      },
    },
  },
});

<span class="hljs-keyword">const</span> BATCH_SIZE = <span class="hljs-number">200</span>;
<span class="hljs-keyword">const</span> CHUNK_SIZE = <span class="hljs-number">3</span>;
<span class="hljs-keyword">const</span> MAX_LINES = <span class="hljs-literal">Infinity</span>;
<span class="hljs-keyword">const</span> DATA_FILE = <span class="hljs-string">"./dataset/songs.json"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">extractUrls</span>(<span class="hljs-params">parsedRecord</span>) </span>{
  <span class="hljs-keyword">return</span> parsedRecord[<span class="hljs-string">"relations"</span>]
    .filter(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span>
      [
        <span class="hljs-string">"amazon asin"</span>,
        <span class="hljs-string">"streaming"</span>,
        <span class="hljs-string">"free streaming"</span>,
        <span class="hljs-string">"download for free"</span>,
        <span class="hljs-string">"purchase for download"</span>,
      ].includes(r[<span class="hljs-string">"type"</span>])
    )
    .map(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">type</span>: r[<span class="hljs-string">"type"</span>], <span class="hljs-attr">url</span>: r[<span class="hljs-string">"url"</span>][<span class="hljs-string">"resource"</span>] };
    });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addSongsToTypesense</span>(<span class="hljs-params">songs, typesense, songsCollection</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> returnDataChunks = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
      _.chunk(songs, <span class="hljs-built_in">Math</span>.ceil(songs.length / CHUNK_SIZE)).map(<span class="hljs-function">(<span class="hljs-params">songsChunk</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> jsonlString = songsChunk
          .map(<span class="hljs-function">(<span class="hljs-params">song</span>) =&gt;</span> stringify(song))
          .join(<span class="hljs-string">"\n"</span>);

        <span class="hljs-keyword">return</span> typesense
          .collections(songsCollection)
          .documents()
          .import(jsonlString);
      })
    );

    <span class="hljs-keyword">const</span> failedItems = returnDataChunks
      .map(<span class="hljs-function">(<span class="hljs-params">returnData</span>) =&gt;</span>
        returnData
          .split(<span class="hljs-string">"\n"</span>)
          .map(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">JSON</span>.parse(r))
          .filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.success === <span class="hljs-literal">false</span>)
      )
      .flat();
    <span class="hljs-keyword">if</span> (failedItems.length &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(
        <span class="hljs-string">`Error indexing items <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(failedItems, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)}</span>`</span>
      );
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client({
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"songsearch"</span>,
  });

  <span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"songs"</span>).delete();

  <span class="hljs-keyword">const</span> songsCollection = <span class="hljs-string">"songs"</span>;
  <span class="hljs-keyword">const</span> schema = {
    <span class="hljs-attr">name</span>: songsCollection,
    <span class="hljs-attr">fields</span>: [
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"track_id"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"title"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"album_name"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"primary_artist_name"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"genres"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string[]"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"country"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_date"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"int64"</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_decade"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
      { <span class="hljs-attr">name</span>: <span class="hljs-string">"release_group_types"</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">"string[]"</span>, <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span> },
    ],
    <span class="hljs-attr">default_sorting_field</span>: <span class="hljs-string">"release_date"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Populating data in Typesense "<span class="hljs-subst">${songsCollection}</span>" collection`</span>);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Creating schema...`</span>);
  <span class="hljs-keyword">await</span> typesense.collections().create(schema);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Songs records...`</span>);

  <span class="hljs-keyword">const</span> fileStream = fs.createReadStream(DATA_FILE);
  <span class="hljs-keyword">const</span> rl = readline.createInterface({
    <span class="hljs-attr">input</span>: fileStream,
    <span class="hljs-attr">crlfDelay</span>: <span class="hljs-literal">Infinity</span>,
  });

  <span class="hljs-keyword">let</span> songs = [];
  <span class="hljs-keyword">let</span> currentLine = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> line <span class="hljs-keyword">of</span> rl) {
    currentLine += <span class="hljs-number">1</span>;
    <span class="hljs-keyword">const</span> parsedRecord = <span class="hljs-built_in">JSON</span>.parse(line);
    <span class="hljs-keyword">try</span> {
      songs.push(
        ...parsedRecord[<span class="hljs-string">"media"</span>]
          .map(<span class="hljs-function">(<span class="hljs-params">media</span>) =&gt;</span> media[<span class="hljs-string">"tracks"</span>])
          .flat()
          .filter(<span class="hljs-function">(<span class="hljs-params">track</span>) =&gt;</span> track) <span class="hljs-comment">// To remove nulls</span>
          .map(<span class="hljs-function">(<span class="hljs-params">track</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> releaseDate =
              <span class="hljs-built_in">Math</span>.round(
                <span class="hljs-built_in">Date</span>.parse(
                  parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"first-release-date"</span>]
                ) / <span class="hljs-number">1000</span>
              ) || <span class="hljs-number">0</span>;

            <span class="hljs-comment">// Be sure to update the schema passed to stringify when updating this structure</span>
            <span class="hljs-keyword">const</span> song = {
              <span class="hljs-attr">track_id</span>: track[<span class="hljs-string">"id"</span>],
              <span class="hljs-attr">title</span>: track[<span class="hljs-string">"title"</span>],
              <span class="hljs-attr">album_name</span>: parsedRecord[<span class="hljs-string">"title"</span>],
              <span class="hljs-attr">primary_artist_name</span>:
                parsedRecord[<span class="hljs-string">"artist-credit"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"artist"</span>][<span class="hljs-string">"name"</span>],
              <span class="hljs-attr">genres</span>: [
                ...track[<span class="hljs-string">"recording"</span>][<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
                ...parsedRecord[<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
                ...parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"genres"</span>].map(<span class="hljs-function">(<span class="hljs-params">g</span>) =&gt;</span> g.name),
              ].map(
                <span class="hljs-function">(<span class="hljs-params">[firstChar, ...rest]</span>) =&gt;</span>
                  firstChar.toUpperCase() + rest.join(<span class="hljs-string">""</span>).toLowerCase()
              ),
              <span class="hljs-attr">country</span>: parsedRecord[<span class="hljs-string">"country"</span>] || <span class="hljs-string">"Unknown"</span>,
              <span class="hljs-attr">release_date</span>: releaseDate,
              <span class="hljs-attr">release_decade</span>: <span class="hljs-string">`<span class="hljs-subst">${
                <span class="hljs-built_in">Math</span>.round(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(releaseDate * <span class="hljs-number">1000</span>).getUTCFullYear() / <span class="hljs-number">10</span>) *
                <span class="hljs-number">10</span>
              }</span>s`</span>,
              <span class="hljs-attr">release_group_types</span>: [
                parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"primary-type"</span>] || <span class="hljs-string">"Unknown"</span>,
                parsedRecord[<span class="hljs-string">"release-group"</span>][<span class="hljs-string">"secondary-types"</span>] || <span class="hljs-literal">null</span>,
              ]
                .flat()
                .filter(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e),
              <span class="hljs-attr">urls</span>: extractUrls(parsedRecord),
            };
            process.stdout.write(<span class="hljs-string">"-"</span>);

            <span class="hljs-keyword">return</span> song;
          })
      );
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">console</span>.error(e);
      <span class="hljs-built_in">console</span>.error(parsedRecord);
      <span class="hljs-keyword">throw</span> e;
    }

    <span class="hljs-keyword">if</span> (currentLine &gt;= MAX_LINES) {
      <span class="hljs-keyword">break</span>;
    }
  }

  <span class="hljs-keyword">if</span> (songs.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">await</span> addSongsToTypesense(songs, typesense, songsCollection);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ALL songs INDEXED ✅ !"</span>);
  }
})();
</code></pre>
<p>Finally, type <code>node loadData.js</code> into the terminal of that same project directory, and you have successfully imported 1 thousand songs documents into the search index.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7g3qqkqc5veb7mkjk02s.png" alt="LoadData" /></p>
<p>Now, you can start your application by typing <code>npm start</code> in the terminal of that project directory.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4ftpt08kj99pmfi15tz.png" alt="npm start" /></p>
<p>We need to fix the fact that the application functions perfectly but no information, as well as data, is displayed in it.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pst64o6j8mmsiwz1yxlm.png" alt="Demo" /></p>
<p>So, to fix it, go to our <code>app.js</code> file and remove a few of the widgets that we don’t need, so the <code>app.js</code> file should look something like this.</p>
<pre><code class="lang-js"><span class="hljs-comment">// app.js</span>
<span class="hljs-keyword">const</span> { instantsearch } = <span class="hljs-built_in">window</span>;

<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"songsearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,primary_artist_name,album_name"</span>, <span class="hljs-comment">//quering by</span>
  },
});
<span class="hljs-keyword">const</span> searchClient = typesenseInstantsearchAdapter.searchClient;

<span class="hljs-keyword">const</span> search = instantsearch({
  searchClient,
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">"songs"</span>,
});

search.addWidgets([
  instantsearch.widgets.searchBox({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#searchbox"</span>,
  }),
  instantsearch.widgets.hits({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#hits"</span>,
  }),
  instantsearch.widgets.pagination({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#pagination"</span>,
  }),
]);

search.start();
</code></pre>
<p>Simply re-run the application after you’ve fixed it, and your application should now look like this.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ingddm581pztolc6mx70.png" alt="Start Server" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/huf9icp5s17vffvlkmy8.png" alt="Data" /></p>
<p>You can now build a search interface using any of the InstantSearch widgets, and we’ll be adding a template to present the data in a pleasing manner.Simplycopy the template code below and add it inside the <code>#hits</code> widget present inside <code>app.js</code> file.</p>
<pre><code class="lang-jsx">templates: {
<span class="hljs-attr">item</span>: <span class="hljs-string">`
&lt;h2&gt;
{ "attribute": "title" }
&lt;/h2&gt;
&lt;div&gt;
by
&lt;a style="color:#FF6F82"&gt;{ "attribute": "primary_artist_name" }&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
Album: &lt;a style="color:#8661d1" &gt;{ "attribute": "album_name" }&lt;/a&gt;
&lt;/div&gt;
&lt;div class="text-muted small mb-2"&gt;
&lt;/div&gt; `</span>,
},
</code></pre>
<p><code>app.js</code> file should resemble something like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">const</span> { instantsearch } = <span class="hljs-built_in">window</span>;

<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">'typesense-instantsearch-adapter'</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">'songsearch'</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">'8108'</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">'http'</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">'title,primary_artist_name,album_name'</span>, <span class="hljs-comment">//quering by</span>
  },
});
<span class="hljs-keyword">const</span> searchClient = typesenseInstantsearchAdapter.searchClient;

<span class="hljs-keyword">const</span> search = instantsearch({
  searchClient,
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">'songs'</span>,
});

search.addWidgets([
  instantsearch.widgets.searchBox({
    <span class="hljs-attr">container</span>: <span class="hljs-string">'#searchbox'</span>,
  }),
  instantsearch.widgets.hits({
    <span class="hljs-attr">container</span>: <span class="hljs-string">'#hits'</span>,
    <span class="hljs-attr">templates</span>: {
      <span class="hljs-attr">item</span>: <span class="hljs-string">`
      &lt;h2&gt;
        { "attribute": "title" }
      &lt;/h2&gt;
      &lt;div&gt;
        by
        &lt;a style="color:#FF6F82"&gt;{ "attribute": "primary_artist_name" }&lt;/a&gt;
      &lt;/div&gt;
      &lt;div&gt;
        Album: &lt;a style="color:#8661d1" &gt;{ "attribute": "album_name" }&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="text-muted small mb-2"&gt;

      &lt;/div&gt;
      `</span>,
    },
  }),
  instantsearch.widgets.pagination({
    <span class="hljs-attr">container</span>: <span class="hljs-string">'#pagination'</span>,
  }),
]);

search.start();
</code></pre>
<p>After you’ve fixed it, re-run the application, and your app should now look like this.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gz7q4665gdfrdzzwoghl.png" alt="Demo" /></p>
<p>Simply add the following code above the <code>#hits</code> widgets inside the <code>app.js</code> file to configure the <code>20 hits per page</code> or to configure to your own requirements.</p>
<pre><code><span class="hljs-selector-tag">instantsearch</span><span class="hljs-selector-class">.widgets</span><span class="hljs-selector-class">.configure</span>({
    <span class="hljs-attribute">hitsPerPage</span>: <span class="hljs-number">20</span>,
  }),
</code></pre><p>So now let’s try to add the facets, to do that we’ll add an instant search widgets .In the <code>instantsearch</code> library this is called <code>refinementlist</code> and finally we have to specify the container, in our case let’s call it a <code>#genreFilter</code>,<code>#artistFilter</code> and then the attribute we want to take, in our case let’s call it genres and <code>primary_artist_name</code> respectively. So, our final code should look like this.</p>
<pre><code class="lang-js"><span class="hljs-comment">// app.js</span>
<span class="hljs-keyword">const</span> { instantsearch } = <span class="hljs-built_in">window</span>;

<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"songsearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,primary_artist_name,album_name"</span>, <span class="hljs-comment">//quering by</span>
  },
});
<span class="hljs-keyword">const</span> searchClient = typesenseInstantsearchAdapter.searchClient;

<span class="hljs-keyword">const</span> search = instantsearch({
  searchClient,
  <span class="hljs-attr">indexName</span>: <span class="hljs-string">"songs"</span>,
});

search.addWidgets([
  instantsearch.widgets.searchBox({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#searchbox"</span>,
  }),
  instantsearch.widgets.configure({
    <span class="hljs-attr">hitsPerPage</span>: <span class="hljs-number">20</span>,
  }),
  instantsearch.widgets.hits({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#hits"</span>,
    <span class="hljs-attr">templates</span>: {
      <span class="hljs-attr">item</span>: <span class="hljs-string">`
      &lt;h2&gt;
        { "attribute": "title" }
      &lt;/h2&gt;
      &lt;div&gt;
        by
        &lt;a style="color:#FF6F82"&gt;{ "attribute": "primary_artist_name" }&lt;/a&gt;
      &lt;/div&gt;
      &lt;div&gt;
        Album: &lt;a style="color:#8661d1" &gt;{ "attribute": "album_name" }&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="text-muted small mb-2"&gt;

      &lt;/div&gt;
      `</span>,
    },
  }),
  instantsearch.widgets.refinementList({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#genreFilter"</span>,
    <span class="hljs-attr">attribute</span>: <span class="hljs-string">"genres"</span>,
    <span class="hljs-attr">searchable</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">searchablePlaceholder</span>: <span class="hljs-string">"Search genres"</span>,
    <span class="hljs-attr">showMore</span>: <span class="hljs-literal">true</span>,
  }),
  instantsearch.widgets.refinementList({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#artistFilter"</span>,
    <span class="hljs-attr">attribute</span>: <span class="hljs-string">"primary_artist_name"</span>,
    <span class="hljs-attr">searchable</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">searchablePlaceholder</span>: <span class="hljs-string">"Search Artist"</span>,
    <span class="hljs-attr">showMore</span>: <span class="hljs-literal">true</span>,
  }),
  instantsearch.widgets.pagination({
    <span class="hljs-attr">container</span>: <span class="hljs-string">"#pagination"</span>,
  }),
]);

search.start();
</code></pre>
<p>and our <code>index.html</code> file should look something like this.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- index.html --&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span>
      <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1, shrink-to-fit=no"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"#000000"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"manifest"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./manifest.webmanifest"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"shortcut icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./favicon.png"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/index.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/app.css"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-title"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-subtitle"</span>&gt;</span>
        using
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com/algolia/instantsearch.js"</span>&gt;</span>
          InstantSearch.js
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__filters"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"genreFilter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"artistFilter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__results"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchbox"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hits"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"pagination"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/algoliasearch@4.10.5/dist/algoliasearch-lite.umd.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.js@4.38.0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./src/app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This is how your application should look like.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bg2x9wilhg8zosk0yno4.png" alt="Final Demo" /></p>
<p>Finally, we can add sorting functionality to the app by repeating the exact steps above: add the <code>sortBy</code> widget, specify the container with <code>#sort-songs</code>, specify the items with the label default with the value <code>songs</code>, and then create another label called <code>Recent songs</code> with the value <code>songs/sort/release_date:asc</code>, and another label called <code>Oldest songs</code> with the value <code>songs/sort/release_date:dsc</code></p>
<pre><code class="lang-js"> instantsearch.widgets.sortBy({
    <span class="hljs-attr">container</span>: <span class="hljs-string">'#sort-songs'</span>,
    <span class="hljs-attr">items</span>: [
      { <span class="hljs-attr">label</span>: <span class="hljs-string">'Default'</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">`songs`</span> },
      { <span class="hljs-attr">label</span>: <span class="hljs-string">'Recent songs'</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">`songs/sort/release_date:asc`</span> },
      { <span class="hljs-attr">label</span>: <span class="hljs-string">'Oldest songs'</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">`songs/sort/release_date:desc`</span> },
    ],
  }),
</code></pre>
<p>Finally, update and add <code>sort-songs</code> id before the <code>searchbox</code> inside <code>index.html</code> file.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- index.html --&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span>
      <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1, shrink-to-fit=no"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"#000000"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"manifest"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./manifest.webmanifest"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"shortcut icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./favicon.png"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/algolia-min.css"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/index.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"./src/app.css"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-title"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>typesense-songsearch<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header-subtitle"</span>&gt;</span>
        using
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com/algolia/instantsearch.js"</span>&gt;</span>
          InstantSearch.js
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__filters"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"genreFilter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"artistFilter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-panel__results"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"sort-songs"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchbox"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hits"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"pagination"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/algoliasearch@4.10.5/dist/algoliasearch-lite.umd.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/instantsearch.js@4.38.0"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./src/app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Let’s take a look at the finished product of our typesense-integrated songsearch application.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fw6q8pbqdyk1ip76lrfb.png" alt="Final Demo" /></p>
<p>The entire source code of the application can be found <a target="_blank" href="https://github.com/aviyelverse/Article-project-demo/tree/main/songs-searchapp-typesense">here</a></p>
<p>Typesense was built with several distinctive features primarily aimed at making the developer’s job easier while also giving customer as well as user the ability to provide a better search experience as possible.This article may have been entertaining as well as instructive in terms of how to create a fullstack song search app using typesense from the ground. Join Aviyel’s community to learn more about the open source project, get tips on how to contribute, and join active dev groups.</p>
<p>Aviyel is a collaborative platform that assists open source project communities in monetizing and long-term sustainability. To know more visit Aviyel.com and find great blogs and events, just like this one! Sign up now for early access, and don’t forget to follow us on our socials!</p>
]]></content:encoded></item><item><title><![CDATA[Anime search app built using Reactjs and Typesense]]></title><description><![CDATA[Creating a search engine that are typo-tolerant, effective, and efficient are exceedingly tough. A typographical error could cause the search to fail even if the desired item is in the database. By removing the requirement to build a search engine fr...]]></description><link>https://pramitmarattha.com.np/anime-search-app-built-using-reactjs-and-typesense</link><guid isPermaLink="true">https://pramitmarattha.com.np/anime-search-app-built-using-reactjs-and-typesense</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[search]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[THW Web Apps]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Sun, 01 May 2022 10:09:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1651399243830/ZmzjECIqm.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Creating a search engine that are typo-tolerant, effective, and efficient are exceedingly tough. A typographical error could cause the search to fail even if the desired item is in the database. By removing the requirement to build a search engine from the ground up, Typesense might save a lot of time and effort. Users will also be able to use the app's search tool successfully, resulting in a positive user experience. Typesense is a free, open-source typo-tolerant search engine for programmers that aims to reduce the amount of time needed to execute effective and efficient searches. To learn more about typesense =&gt;.<a target="_blank" href="https://typesense.org/docs/overview/what-is-typesense.html">What is Typesense, and why is it such a great tool?</a>.</p>
<p>This tutorial will show you how to install Typesense, how to create a Typesense application from the ground up, how to preconfigure the Typesense client, and much more. This article also demonstrates how to establish a Typesense Collection. Finally, we'll start up our program, add a new item to our collection, and search our indexed data/collection.</p>
<p>Let's get started. The goal of this article is to create an instant search type application, also known as "search as you type," which means that whenever you type something, the results appear instantly, providing a pleasant user experience. So, in a previous article, we created a simple <a target="_blank" href="https://aviyel-blogs.netlify.app/book-search-app-typesense/">Typesense Booksearch</a> javascript application, and in this article, we'll built an <code>Anime search</code> but by using Animes dataset and also by using react.js, with the goal of simply showing you how to do it using the most popular framework or UI library.So let's get started with our <code>React js</code> application with <code>Javascript</code>. To do so, simply follow the instructions below.</p>
<h3 id="heading-configuring-our-react-application">Configuring our React application</h3>
<p>We'll begin by using <code>create-react-app</code> to set up our frontend. We'll build the user interface and its features from the ground up. Let's go to work on our application right away.</p>
<h3 id="heading-setting-up-react-application-bootstarpped-using-cra">Setting up react application bootstarpped using <code>CRA</code></h3>
<p>Let's start with the react part and start building it. The first thing you need do is install <code>Node.js</code> if it isn't already installed on your PC. So, head over to the official <a target="_blank" href="https://nodejs.org/">Node.js</a> website and download the latest version. Node js is required in order to use the node package manager, generally known as <code>npm</code>. Now open the folder in your preferred code editor. we'll be using VScode code editor for this article tutorial . Next, open the integrated terminal and type <code>npx create-react-app</code> . This command will create a react application in the current directory.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/153816630-8ed3ba27-7a5e-4bd2-b933-9b66aceebaba.png" alt="create react app" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/153816904-c1e86e57-b16c-4a30-8c23-220c3a5570bc.png" alt="installation" /></p>
<p>It normally only takes a few minutes to set up. Normally, we would use npm to get packages into a project, but in this case, we'll use npx, the package runner, which will download and configure everything for us so that we can get started with an excellent template right away. It's time to start our development server, so run <code>npm start</code> and the browser will open react-app instantly.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635330419245-image-resized.png" alt="Starting react app" /></p>
<p>So, this is how the boilerplate template appears right away. Now it's time to investigate the file and folder structure provided by create-react-app. There is a folder called node module that contains all of our node dependencies. Then there's a public folder, where the only thing that matters is the index.html file. So this appears to be a standard HTML file, complete with head, body, and meta tags. You'll notice a div with the id root inside our body tag, followed by the fallback noscript tag, which will be visible only if the user's browser has javascript disabled.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!--index.html--&gt;</span>

<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/favicon.ico"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"#000000"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
      <span class="hljs-attr">content</span>=<span class="hljs-string">"Web site created using create-react-app"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"apple-touch-icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/logo192.png"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"manifest"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"%PUBLIC_URL%/manifest.json"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>React practice<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">noscript</span>&gt;</span>You need to enable JavaScript to run this app.<span class="hljs-tag">&lt;/<span class="hljs-name">noscript</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>So you're probably wondering where the content comes from. Remember that, All of our source code is contained within our source or src folder, and react will inject it into the root div element. Let's take a look at our src folder, which contains some stylesheets, javascript files, and SVG files.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1634549337152-image.png" alt="src directory" /></p>
<p>Now, head over to our App.js file</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>

<span class="hljs-keyword">import</span> logo <span class="hljs-keyword">from</span> <span class="hljs-string">"./logo.svg"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{logo}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App-logo"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"logo"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          Edit <span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>src/App.js<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span> and save to reload.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"App-link"</span>
          <span class="hljs-attr">href</span>=<span class="hljs-string">"https://reactjs.org"</span>
          <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
          <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>
        &gt;</span>
          Learn React
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>In this case, we're simply importing react from react and logo from our logo using standard javascript. Following that, we have a normal javascript function called APP, and this function in react is known as a functional component, and this function is returning a react-element that looks like HTML but is actually an jsx as you can see there is a div tag with a className of APP, and we can't say class by itself because the class is a reserved word in javascript, so in jsx we have to use className. Following that, we have the header and then the image, and notice on the image source that we have our logo, which is actually a javascript variable that we imported at the top, so in order to use the javascript within JSX, we must surround it with curly brackets, and then we have a paragraph, an anchor tag, and that is all for this component.</p>
<blockquote>
<p>NOTE: Because of the export, we are able to extract the component and place it on the webpage. Export appears at the bottom of the app.js file, indicating that we are exporting the App function.</p>
</blockquote>
<p>So, Now let's look at the index.js file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;
<span class="hljs-keyword">import</span> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">"./reportWebVitals"</span>;

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)
);
reportWebVitals();
</code></pre>
<p>So, in this case, we're importing react from react again, and this time we're also importing react-dom, and then we're importing the CSS stylesheet file, and finally, we're importing App from App.js, which is the file we just discussed, and there's service worker, which is used to make your application work completely offline. Then we invoke ReactDom.render, which accepts two parameters. The first parameter is the jsx object, and within jsx we can include our user-defined components, so react strict mode is a react defined component, whereas App is a user-defined component, and the second parameter is document.getElementById('root'), which targets the root div in our index.html file and is how we access the content in our webpage.</p>
<blockquote>
<p>Note: ReactDom renders our content into our root div located at our index.html file.</p>
</blockquote>
<h3 id="heading-react-boilerplate-files-cleanup">React boilerplate files cleanup</h3>
<p>We must first tidy up our projects by eliminating some of the files provided by create-react-app before we can begin creating them. After you've cleaned up your files and folder , they should look like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/153834115-57bff3c4-7fb5-48b1-9e76-4d1e76a15870.png" alt="Folder structure" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1637492376405-image.png" alt="Folder Structure" /></p>
<h3 id="heading-adding-and-installing-some-packages">Adding and Installing some packages</h3>
<p>We will need to install a few third-party packages for this project. so copy and paste the following command into your terminal</p>
<h4 id="heading-installing-typesense">Installing <code>typesense</code></h4>
<p>This is going to be our primary typesense package.</p>
<pre><code class="lang-bash">npm install typesense
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/153822802-9c470db7-fc72-4b0b-bdf9-95f0daaea8e0.png" alt="typesense" /></p>
<h4 id="heading-installing-typesense-instantsearch-adapter">Installing <code>typesense-instantsearch-adapter</code></h4>
<p>This package will allow us to use the instantsearch UI, and this adapter will basically plug it into typesense because <code>instantsearch.js</code> is created by algolia, but typesense created this adapter to port its functionality and features into the <code>typesense</code> package itself.</p>
<pre><code class="lang-bash">npm install typesense-instantsearch-adapter
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/153867877-cd116cdc-4cbf-43bc-a292-e6c311ad40b7.png" alt="typesense-instantsearch-adapter" /></p>
<h4 id="heading-installing-styled-components">Installing <code>styled-components</code></h4>
<p>This package will lets you write actual CSS inside your JavaScript project.</p>
<pre><code class="lang-bash">npm install styled-components
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/153822925-64929f93-6321-42e1-a30c-3dbfa2177dcd.png" alt="styled-components" /></p>
<h4 id="heading-installing-instantsearchcss">Installing <code>instantsearch.css</code></h4>
<p>Instead of creating everything from scratch, this package will give pre-made styles such as the search box and numerous UI styles.</p>
<pre><code class="lang-bash">npm install instantsearch.css
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/153822716-176579e2-7276-4499-968f-9ab81067a282.png" alt="instantsearch.css" /></p>
<h4 id="heading-installing-react-instantsearch-dom">Installing <code>react-instantsearch-dom</code></h4>
<p>This package is the React version of Algolia's <code>instantsearch.js</code> library which will provides us the components that we need render it onto our projects.</p>
<p>This package wil</p>
<pre><code class="lang-bash">npm install react-instantsearch-dom
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/153825008-dc740c1f-8be4-4746-9e38-eb52830eb74e.png" alt="react-instantsearch-dom" /></p>
<p>Finally, your <code>package.json</code> file should look like this once you've installed all of your project's dependencies.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"anime-searchapp-reactjs-typesense"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.14.1"</span>,
    <span class="hljs-attr">"@testing-library/react"</span>: <span class="hljs-string">"^12.0.0"</span>,
    <span class="hljs-attr">"@testing-library/user-event"</span>: <span class="hljs-string">"^13.2.1"</span>,
    <span class="hljs-attr">"instantsearch.css"</span>: <span class="hljs-string">"^7.4.5"</span>,
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-instantsearch-dom"</span>: <span class="hljs-string">"^6.22.0"</span>,
    <span class="hljs-attr">"react-scripts"</span>: <span class="hljs-string">"5.0.0"</span>,
    <span class="hljs-attr">"styled-components"</span>: <span class="hljs-string">"^5.3.3"</span>,
    <span class="hljs-attr">"typesense"</span>: <span class="hljs-string">"^1.1.3"</span>,
    <span class="hljs-attr">"typesense-instantsearch-adapter"</span>: <span class="hljs-string">"^2.3.0"</span>,
    <span class="hljs-attr">"web-vitals"</span>: <span class="hljs-string">"^2.1.0"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"react-scripts test"</span>,
    <span class="hljs-attr">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>
  },
  <span class="hljs-attr">"eslintConfig"</span>: {
    <span class="hljs-attr">"extends"</span>: [<span class="hljs-string">"react-app"</span>, <span class="hljs-string">"react-app/jest"</span>]
  },
  <span class="hljs-attr">"browserslist"</span>: {
    <span class="hljs-attr">"production"</span>: [<span class="hljs-string">"&gt;0.2%"</span>, <span class="hljs-string">"not dead"</span>, <span class="hljs-string">"not op_mini all"</span>],
    <span class="hljs-attr">"development"</span>: [
      <span class="hljs-string">"last 1 chrome version"</span>,
      <span class="hljs-string">"last 1 firefox version"</span>,
      <span class="hljs-string">"last 1 safari version"</span>
    ]
  }
}
</code></pre>
<p>Now that our project and dependencies have been set up, we can get started.Firstly, we need to import our <code>animes</code> data, so create a dataset folder and inside it, create your own anime list json file, filling it with all of the necessary product information, or download the anime dataset from <a target="_blank" href="https://github.com/aviyelverse/Article-project-demo/tree/main/anime-searchapp-reactjs-typesense/dataset">here</a>. Finally, your folder structure and dataset should look something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/153834730-26d1d0bf-acab-4243-8c48-ead978d2adf4.png" alt="folder structure" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/153834813-0d9e17fb-1670-4a1c-b31e-52f65d0ac97b.png" alt="dataset" /></p>
<p>So, in order to populate our Typesense index, we must first start our Typesense server, and there are several ways to do so. There is the old programmatic way, which requires you to install everything, start it up, and provide the configuration using code, or there is this one awesome method, which is the preferred method, which is very steady and known to work, and which is used in the docker image and run the docker container that will basically bind and give it a volume that will connect to where you'll be storing the data, and that's all there is to it.So that's essentially what we'll be using in this article.</p>
<p>Let's start by creating a new script and a folder called <code>scripts</code>, because we'll have a handful of scripts loaded in here that will allow us to either index the data or start the typesense server or the docker container, so you can basically put it inside the script run tag inside the <code>package.json</code>.So that, every time you wish to start the server, you can just open up the command prompt and fire up the npm command</p>
<p>Inside the <code>scripts</code> folder, create a new file called <code>runServer.js</code>. So, this script will essentially run the docker command, but before we do so, we must first configure it. Folder structure should resemble something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/153859923-e63898c3-310a-48fb-91c3-37bf92777095.png" alt="Folder structure script" /></p>
<p>The very First step is to execute command from the child process of node.js.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// runServer.js</span>
<span class="hljs-keyword">const</span> { exec } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"child_process"</span>);
</code></pre>
<p>Next, let's set up the command. We'll use docker -run and detach to run the docker in the background, then assign the port. The most important section of this command is the volume section. What we're doing here is binding the volume, which is essentially a way to store the data of the typesense, which by default is inside the container itself.So, typesense will store the data inside the container's data folder named <code>/data</code>, and it will expose and link this <code>/data</code> folder into the folder we designate on our system, which in this case will be the <code>tmp</code> directory. This approach will assist to keep the data consistent and ensure that it is resilient, and we will always preserve the data so that if the docker container is deleted, stopped, or something similar happens, we will simply keep our data in a secure place. By specifying a <code>-v</code> volume, we are just indicating where we want the data to be stored . After that, we need to specify which image is required to run inside our docker container, so we'll use <code>typesense/typesense:0.22.2</code> for now, but you can use your own image, and then specify the data directory and the api key, which you can put anything you want and pass the listen port, and finally enable CORS so we don't have any <code>CORS</code> related issues. This is what your code should look like.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// runServer.js</span>
<span class="hljs-keyword">const</span> { exec } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"child_process"</span>);

<span class="hljs-keyword">const</span> command = <span class="hljs-string">`docker run -d -p 8108:8108 -v/tmp/typesense-server-data/:/data \ typesense/typesense:0.22.2 --data-dir /data --api-key=animesearch --listen-port 8108 --enable-cors`</span>;
</code></pre>
<p>Finally, we must run the command and simply construct an error handler in the event that an error happens while running the commands. As a result, your final "runServer" code should look like this.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// runServer.js</span>
<span class="hljs-keyword">const</span> { exec } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"child_process"</span>);

<span class="hljs-keyword">const</span> command = <span class="hljs-string">`docker run -d -p 8108:8108 -v/tmp/typesense-server-data/:/data \ typesense/typesense:0.22.2 --data-dir /data --api-key=animesearch --listen-port 8108 --enable-cors`</span>;

exec(command, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!err) <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Typesense Server is up and running...✰✨"</span>);

  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error running server: "</span>, err);
  }
});
</code></pre>
<p>So now that we have our <code>runServer.js</code> script ready to go, we can simply update the script tag in our <code>package.json</code> file.Finally, your <code>package.json</code> file should look like this once you've updated the script.</p>
<pre><code class="lang-json"><span class="hljs-comment">// package.json</span>
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"anime-searchapp-reactjs-typesense"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.14.1"</span>,
    <span class="hljs-attr">"@testing-library/react"</span>: <span class="hljs-string">"^12.0.0"</span>,
    <span class="hljs-attr">"@testing-library/user-event"</span>: <span class="hljs-string">"^13.2.1"</span>,
    <span class="hljs-attr">"instantsearch.css"</span>: <span class="hljs-string">"^7.4.5"</span>,
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-instantsearch-dom"</span>: <span class="hljs-string">"^6.22.0"</span>,
    <span class="hljs-attr">"react-scripts"</span>: <span class="hljs-string">"5.0.0"</span>,
    <span class="hljs-attr">"styled-components"</span>: <span class="hljs-string">"^5.3.3"</span>,
    <span class="hljs-attr">"typesense"</span>: <span class="hljs-string">"^1.1.3"</span>,
    <span class="hljs-attr">"typesense-instantsearch-adapter"</span>: <span class="hljs-string">"^2.3.0"</span>,
    <span class="hljs-attr">"web-vitals"</span>: <span class="hljs-string">"^2.1.0"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"react-scripts test"</span>,
    <span class="hljs-attr">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>,
    <span class="hljs-attr">"start-server"</span>: <span class="hljs-string">"node scripts/runServer.js"</span>
  },
  <span class="hljs-attr">"eslintConfig"</span>: {
    <span class="hljs-attr">"extends"</span>: [<span class="hljs-string">"react-app"</span>, <span class="hljs-string">"react-app/jest"</span>]
  },
  <span class="hljs-attr">"browserslist"</span>: {
    <span class="hljs-attr">"production"</span>: [<span class="hljs-string">"&gt;0.2%"</span>, <span class="hljs-string">"not dead"</span>, <span class="hljs-string">"not op_mini all"</span>],
    <span class="hljs-attr">"development"</span>: [
      <span class="hljs-string">"last 1 chrome version"</span>,
      <span class="hljs-string">"last 1 firefox version"</span>,
      <span class="hljs-string">"last 1 safari version"</span>
    ]
  }
}
</code></pre>
<p>Finally, start the server by typing <code>npm run start-server</code>, and your docker will start running, then you can proceed to the next step of indexing the data/collection.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/153864597-1da14c82-4108-48e2-aa37-a59a2959eb44.png" alt="npm run server script" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/153864983-cfae4c1b-1bf9-457e-a4b1-6278e43d35b0.png" alt="Docker running" /></p>
<p>The next step is to actually populate or index the data inside the typesense server, so now that we have the server up and running and a bunch of anime data, this is the datset that we want to populate inside the typesense server so that later on in our UI we can basically query that typesense server and do an instant search that will be legit incredibly fast.So to do that let's get started writing the data-importing scripts. We'll start by creating a file called <code>loadData.js</code> inside the <code>scripts</code> folder which we previously created in which we'll initialize the typesense client.</p>
<h3 id="heading-indexing-data-on-typesense-a-step-by-step-guide">Indexing data on typesense: a step-by-step guide</h3>
<p><strong><em>First step</em></strong>: We need to import the <code>Typesense</code> library to our project.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);
</code></pre>
<p><strong><em>Seecond step</em></strong>: Let's go ahead and make a self-executing function that will run whenever we run the script and make it asynchronous so we can use the async await functionality. Simply create'module.export' and export the self-executing function inside it and make it asynchronous so we can make a script that reads the data and does the collection, manages the typesense server, and indexes the data. So the first thing we need to do is set up the typesense client so that we can connect to the server and begin managing, indexing, and retrieving data.
So first create a typesense config variable and pass the <code>nodes</code> properties first. So what it does is it allows you to have multiple nodes for a single server, for example, a client can connect to multiple nodes, and nodes are basically just servers, so this specific <code>nodes</code> is actually an array that holds the actual configuration for each server that you actually want to connect into and that you want the client to access, so currently we only have one server running so we are going to usitlize only one <code>nodes</code>.Next, inside the <code>nodes</code> array, supply the host, typesense port, and protocol it uses, as well as the api key.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> TYPESENSE_CONFIG = {
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
  };
})();
</code></pre>
<p><strong><em>Third step</em></strong>: Let's utilize the typesense configuration to make a Typesense client.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> TYPESENSE_CONFIG = {
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Config: "</span>, TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client(TYPESENSE_CONFIG);
})();
</code></pre>
<p><strong><em>Fourth step</em></strong>: This is a crucial stage because it is here that we provide the <code>schema</code> that will have our data indexed into the actual typesense database, therefore <code>schema</code> is quite critical. It's fairly basic syntax and super simple to work with. Schema is basically where you describe how your data is going to be saved. For our <code>schema</code>, we have title, synopsis, genre, aired, popularity, ranking, score, img url, and links. So in <code>schema</code> you only want to put the fields you wish to index.If you're familiar with nosql databases, especially mongodb, it's heavily inspired by this approach. If you're familiar with the <code>mongoose ORM(Object Relational Model)</code> for example: how it works and how you can retrieve data and collections, it basically works the same way and and typesense has this particular exact feature. So it's basically like a nosql database . It's a little more sophisticated than that, but you may think of it like this to get a general impression of it and understand how the data flows, and how it's all organized together.Begin by giving the schema a name and making sure the number of documents is set to zero. Next, add the fields, which will be an array of objects containing every single field that we want to index and store in our database, so provide the name, type, and facet. So, if you're wondering what facet is, it's a feature that allows you to define categories based on a subset of attributes so that users may narrow down their search results.This is how your schema should look like.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> TYPESENSE_CONFIG = {
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Config: "</span>, TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client(TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> schema = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"animes"</span>,
    <span class="hljs-attr">num_documents</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">fields</span>: [
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"title"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"synopsis"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl0"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl1"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl2"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl3"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl4"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl5"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"aired"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"popularity"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"ranked"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"score"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"img_url"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"link"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
    ],
    <span class="hljs-attr">default_sorting_field</span>: <span class="hljs-string">"popularity"</span>,
  };
})();
</code></pre>
<p>So, if you want to index all of the data in the array of genres, for example, you'll need to store store each level of the array on threir specific/own field.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154030644-8456b82f-3493-4363-bd85-98179a176ced.png" alt="level" /></p>
<p>Let's proceed to our dataset and look at the genres section. As you can see in the figure below, there are four items in that array, so we will make each field level for each of them items.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154032927-fdbd874b-a897-458f-ab50-1df5eb71954b.png" alt="genres" /></p>
<p><strong><em>Fifth step</em></strong>: Let's start by reading the movies from the json files and then importing the dataset. Now is the time to call the Typesense client and establish a connection with a schema within it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> TYPESENSE_CONFIG = {
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Config: "</span>, TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client(TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> schema = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"animes"</span>,
    <span class="hljs-attr">num_documents</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">fields</span>: [
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"title"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"synopsis"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl0"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl1"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl2"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl3"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl4"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl5"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"aired"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"popularity"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"ranked"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"score"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"img_url"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"link"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
    ],
    <span class="hljs-attr">default_sorting_field</span>: <span class="hljs-string">"popularity"</span>,
  };

  <span class="hljs-keyword">const</span> animes = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../dataset/animes.json"</span>);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> collection = <span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"animes"</span>).retrieve();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Found existing collection of animes"</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">JSON</span>.stringify(collection, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
})();
</code></pre>
<p><strong><em>Sixth step</em></strong>: If an error occurs while loading the data(data duplication error), simply add the following snippet of code to the <code>loadData.js</code> file before creating <code>schema</code> becasue it will simply remove the existing data and populates it with the new ones.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (collection.num_documents !== animes.length) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Collection has diff number of docs than data"</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Deleting collection"</span>);
  <span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"animes"</span>).delete();
}
</code></pre>
<p><strong><em>Seventh step</em></strong>: Creating a collection named <code>animes</code> . In Typesense a Collection is a set of related Documents that functions similarly to a table in a relational database. We give a collection a name and describe the fields that will be indexed when a document is added to the collection when we create it.</p>
<p>Your final code inside <code>loadData.js</code> file should look like this.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// loadData.js</span>
<span class="hljs-keyword">const</span> Typesense = <span class="hljs-built_in">require</span>(<span class="hljs-string">"typesense"</span>);

<span class="hljs-built_in">module</span>.exports = (<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> TYPESENSE_CONFIG = {
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Config: "</span>, TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> typesense = <span class="hljs-keyword">new</span> Typesense.Client(TYPESENSE_CONFIG);

  <span class="hljs-keyword">const</span> schema = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"animes"</span>,
    <span class="hljs-attr">num_documents</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">fields</span>: [
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"title"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"synopsis"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">false</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl0"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl1"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl2"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl3"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl4"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"genre.lvl5"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"auto"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">optional</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"aired"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"popularity"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"ranked"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"float"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"score"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"img_url"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
      {
        <span class="hljs-attr">name</span>: <span class="hljs-string">"link"</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">facet</span>: <span class="hljs-literal">true</span>,
      },
    ],
    <span class="hljs-attr">default_sorting_field</span>: <span class="hljs-string">"popularity"</span>,
  };

  <span class="hljs-keyword">const</span> animes = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../dataset/animes.json"</span>);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> collection = <span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"animes"</span>).retrieve();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Found existing collection of animes"</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">JSON</span>.stringify(collection, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));

    <span class="hljs-keyword">if</span> (collection.num_documents !== animes.length) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Collection has diff number of docs than data"</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Deleting collection"</span>);
      <span class="hljs-keyword">await</span> typesense.collections(<span class="hljs-string">"animes"</span>).delete();
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Creating schema..."</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">JSON</span>.stringify(schema, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));

  <span class="hljs-keyword">await</span> typesense.collections().create(schema);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Populating collection data..."</span>);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> returnData = <span class="hljs-keyword">await</span> typesense
      .collections(<span class="hljs-string">"animes"</span>)
      .documents()
      .import(animes);

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Return data: "</span>, returnData);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
})();
</code></pre>
<p>So now that we have our <code>loadData.js</code> script ready to go, we can simply update the script tag in our <code>package.json</code> file.Finally, your <code>package.json</code> file should look like this once you've updated the script.</p>
<pre><code class="lang-json"><span class="hljs-comment">// package.json</span>
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"anime-searchapp-reactjs-typesense"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.14.1"</span>,
    <span class="hljs-attr">"@testing-library/react"</span>: <span class="hljs-string">"^12.0.0"</span>,
    <span class="hljs-attr">"@testing-library/user-event"</span>: <span class="hljs-string">"^13.2.1"</span>,
    <span class="hljs-attr">"instantsearch.css"</span>: <span class="hljs-string">"^7.4.5"</span>,
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-instantsearch-dom"</span>: <span class="hljs-string">"^6.22.0"</span>,
    <span class="hljs-attr">"react-scripts"</span>: <span class="hljs-string">"5.0.0"</span>,
    <span class="hljs-attr">"styled-components"</span>: <span class="hljs-string">"^5.3.3"</span>,
    <span class="hljs-attr">"typesense"</span>: <span class="hljs-string">"^1.1.3"</span>,
    <span class="hljs-attr">"typesense-instantsearch-adapter"</span>: <span class="hljs-string">"^2.3.0"</span>,
    <span class="hljs-attr">"web-vitals"</span>: <span class="hljs-string">"^2.1.0"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"react-scripts test"</span>,
    <span class="hljs-attr">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>,
    <span class="hljs-attr">"start-server"</span>: <span class="hljs-string">"node scripts/runServer.js"</span>,
    <span class="hljs-attr">"indexer"</span>: <span class="hljs-string">"node scripts/loadData.js"</span>
  },
  <span class="hljs-attr">"eslintConfig"</span>: {
    <span class="hljs-attr">"extends"</span>: [<span class="hljs-string">"react-app"</span>, <span class="hljs-string">"react-app/jest"</span>]
  },
  <span class="hljs-attr">"browserslist"</span>: {
    <span class="hljs-attr">"production"</span>: [<span class="hljs-string">"&gt;0.2%"</span>, <span class="hljs-string">"not dead"</span>, <span class="hljs-string">"not op_mini all"</span>],
    <span class="hljs-attr">"development"</span>: [
      <span class="hljs-string">"last 1 chrome version"</span>,
      <span class="hljs-string">"last 1 firefox version"</span>,
      <span class="hljs-string">"last 1 safari version"</span>
    ]
  }
}
</code></pre>
<p>Finally, start indexing the data in typesense server by typing <code>npm run indexer</code>, and your data will start getting populated inside the typesense server.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154106281-60da1d4d-4a60-40c8-930f-edbbc42e85a8.png" alt="populating" />
<img src="https://user-images.githubusercontent.com/37651620/154106362-44a66dd3-9cb2-43ec-8ba6-cab29334fe48.png" alt="populating" />
<img src="https://user-images.githubusercontent.com/37651620/154106436-5c034f43-b2fe-494a-a4c2-36c5de498fe1.png" alt="populating" />
<img src="https://user-images.githubusercontent.com/37651620/154106488-fcc54bc6-4607-43e6-8f7e-8954a9d67fbb.png" alt="populating" /></p>
<h3 id="heading-building-a-ui-and-retrieving-the-data">Building a UI and retrieving the data</h3>
<p>Let's get started by putting together the UI. Our frontend, or UI, will need to connect to the typesense server and do queries. A Typesense server is as standard and flexible as any other HTTP server. You can basically send the HTTP request, which we will be utilizing here as well, and the client will simply submit a normal HTTP request and it will do the search for you. That is basically how it will operate between a client and the actual typesense server.</p>
<p>So, before we perform any UI work or display or render any components, we must first connect to the server and supply the configuration that we accomplished previously.We can now finally adjust the project to use Typesense.We've got our typesense instance up and running in the background.To get React to use the Typesense adapter, open <code>src/app.js</code> file and create a connection first. Inside that, create a <code>TypesenseInstantsearchAdapter</code> object and add <code>server</code> as a key. Inside that, pass the <code>apiKey</code> and <code>nodes</code>, and inside the <code>nodes</code>, specify the <code>host</code>, <code>port</code>, and <code>protocol</code>. Finally, add the additional search parameter to it and pass the <code>query</code> and <code>queryByWeight</code> which you want to display the indexed document/data accordingly.(Remember that these parameters are passed directly to the Typesense search API endpoint. As a result, any parameters supported by the search endpoint can be passed through it).</p>
<p>The following is an example of what your code should look like.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"titles,synopsis,genre"</span>,
    <span class="hljs-attr">queryByWeights</span>: <span class="hljs-string">"4,2,1"</span>,
    <span class="hljs-attr">numTypos</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">typoTokensThreshold</span>: <span class="hljs-number">1</span>,
  },
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now that we've completed the configuration, let's move on to creating an interface for our application. To do so, first import the <code>InstantSearch</code> component from the <code>react-instantsearch-dom</code> library, and pass <code>indexName</code> and <code>searchClient</code> as props to that component.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// app.js</span>
<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;
<span class="hljs-keyword">import</span> { InstantSearch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-instantsearch-dom"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"titles,synopsis,genre"</span>,
    <span class="hljs-attr">queryByWeights</span>: <span class="hljs-string">"4,2,1"</span>,
    <span class="hljs-attr">numTypos</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">typoTokensThreshold</span>: <span class="hljs-number">1</span>,
  },
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InstantSearch</span>
        <span class="hljs-attr">indexName</span>=<span class="hljs-string">"animes"</span>
        <span class="hljs-attr">searchClient</span>=<span class="hljs-string">{typesenseInstantsearchAdapter.searchClient}</span>
      &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">InstantSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>If you start your " react.js" application, it will appear empty.</p>
<p>Before we dive into integrating searchbox, let's style our application and segregate the search section, as well as add some style to our interface, so simply follow the code below and wrap it inside the <code>InstantSearch</code> component.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InstantSearch</span>
        <span class="hljs-attr">indexName</span>=<span class="hljs-string">"animes"</span>
        <span class="hljs-attr">searchClient</span>=<span class="hljs-string">{typesenseInstantsearchAdapter.searchClient}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">aside</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"results-section"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>Search/result section<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">InstantSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
</code></pre>
<p>Now let's add the <code>SearchBox</code> and <code>Hits</code> components from the <code>react-instantsearch-dom</code> library, so we can directly incorporate those components inside our application.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;
<span class="hljs-keyword">import</span> ResultTemplate <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ResultTemplate"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> {
  InstantSearch,
  SearchBox,
  Hits,
  Configure,
  Pagination,
  SortBy,
  Panel,
  RefinementList,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-instantsearch-dom"</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"instantsearch.css/themes/satellite.css"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,synopsis,genre"</span>,
    <span class="hljs-attr">queryByWeights</span>: <span class="hljs-string">"4,2,1"</span>,
    <span class="hljs-attr">numTypos</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">typoTokensThreshold</span>: <span class="hljs-number">1</span>,
  },
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"super-title"</span>&gt;</span>
        👊🏻👨🏻‍🦲Anime search application built using react👺🔪👿
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InstantSearch</span>
        <span class="hljs-attr">indexName</span>=<span class="hljs-string">"animes"</span>
        <span class="hljs-attr">searchClient</span>=<span class="hljs-string">{typesenseInstantsearchAdapter.searchClient}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Configure</span> <span class="hljs-attr">hitsPerPage</span>=<span class="hljs-string">{12}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">aside</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"results-section"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"searchbox-gap"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Hits</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">InstantSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Simply re-run the application after you've fixed it, and your application should now look like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154143573-2d0c9885-49c3-417a-9d98-22745bbc237b.png" alt="Demo" /></p>
<p>At the moment, our data is shown in json format, same like it is in our index. Let's present the data in a more appealing way, therefore let's make a new component folder and inside that folder create another new file called <code>ResultTemplate.js</code> and pass the the <code>hit</code> props. Finally, show the anime title by simply passing <code>{hit.title}</code> and wrapping it in a simple <code>div</code> tag.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ResultTemplate</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> ResultTemplate = <span class="hljs-function">(<span class="hljs-params">{ hit }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{hit.title}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ResultTemplate;
</code></pre>
<p>After you've finished creating a component, simply import it into the App.js file and feed it to the Hit component.</p>
<pre><code class="lang-jsx">&lt;Hits hitComponent={ResultTemplate} /&gt;
</code></pre>
<p>Simply re-run the application after you've fixed it, and it should now appear like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154143750-4c8027ef-89b2-4b71-92d8-99593306928a.png" alt="Demo" /></p>
<p>So, let's add some styling to our app to make the results display in a grid format, so head to the app's main page and inspect the element there.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154143956-6727e9f3-bf7f-4dcb-90d5-8bf253ef369c.png" alt="inspect" /></p>
<p>So the concept here with this reactInstanceSearch library is that those elements have predefined classes names, as you can see each element has an <code>ais-Hits</code>,<code>ais-Hits-lists</code> and then you have <code>ais-Hits-items</code>. so we just need to change the styles and because we're using vanilla css approach, we'll use the grid of four columns so let's save the application and simply re-run it.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* App.css */</span>
<span class="hljs-selector-class">.ais-Hits-list</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, minmax(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}
</code></pre>
<p>Also, don't forget to make some changes to the styles <code>ResultTemplate</code> before re-running the application.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ResultTemplate</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> ResultTemplate = <span class="hljs-function">(<span class="hljs-params">{ hit }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-wrapper"</span>&gt;</span>{hit.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ResultTemplate;
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.anime-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.anime-wrapper</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
}
</code></pre>
<p>and the application should now look something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154145436-e2e56c4a-299b-418e-bb42-108f7663fbeb.png" alt="image" /></p>
<p>It's time to display some images of our anime movies, so we'll use the "img" tag and simply pass<code>{hit.image_url}</code> as an image source, followed by the styles.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ResultTemplate</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> ResultTemplate = <span class="hljs-function">(<span class="hljs-params">{ hit }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-wrapper"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-image"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{hit.img_url}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"movie"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{hit.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ResultTemplate;
</code></pre>
<h4 id="heading-styles">Styles</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* App.css */</span>
<span class="hljs-selector-class">.anime-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.anime-wrapper</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.anime-image</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
}

<span class="hljs-selector-class">.ais-Hits-list</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, minmax(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}
</code></pre>
<p>It's time to set up the list of <code>hits</code> that will appear on your page, simply add the Configure component and specify the <code>hitsPerPage</code> option to configure the list of <code>hits</code> that you want to display in your page. Finally, use the <code>Pagination</code> widgets offered by the <code>react-instantsearch-dom</code> library to add pagination. Also, let's try adding facets. To do so, we'll add a widget, which in the <code>react-instanctsearch-dom</code> library is named <code>RefinementList</code>, and then define the attribute we want to take, which in our instance would be <code>genre</code>, and also for labeling add the <code>Panel</code> component as well so Finally, re-run the application. As a result, your completed code should look like this...</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;
<span class="hljs-keyword">import</span> ResultTemplate <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ResultTemplate"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> {
  InstantSearch,
  SearchBox,
  Hits,
  Configure,
  Pagination,
  Panel,
  RefinementList,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-instantsearch-dom"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,synopsis,genre"</span>,
    <span class="hljs-attr">queryByWeights</span>: <span class="hljs-string">"4,2,1"</span>,
    <span class="hljs-attr">numTypos</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">typoTokensThreshold</span>: <span class="hljs-number">1</span>,
  },
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"super-title"</span>&gt;</span>
        👊🏻👨🏻‍🦲Anime search application built using react👺🔪👿
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">InstantSearch</span>
        <span class="hljs-attr">indexName</span>=<span class="hljs-string">"animes"</span>
        <span class="hljs-attr">searchClient</span>=<span class="hljs-string">{typesenseInstantsearchAdapter.searchClient}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Configure</span> <span class="hljs-attr">hitsPerPage</span>=<span class="hljs-string">{12}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">aside</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"results-section"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Popularity"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Genre"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">RefinementList</span>
                <span class="hljs-attr">attribute</span>=<span class="hljs-string">"genre"</span>
                <span class="hljs-attr">transformItems</span>=<span class="hljs-string">{(items)</span> =&gt;</span>
                  items.map((item) =&gt; ({
                    ...item,
                    label: item.label.slice(2, -2),
                  }))
                }
                searchable={true}
                showMore={true}
                limit={10}
                showMoreText="Show more"
                showLessText="Show less"
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Aired"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">RefinementList</span> <span class="hljs-attr">attribute</span>=<span class="hljs-string">"aired"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"searchbox-gap"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Hits</span> <span class="hljs-attr">hitComponent</span>=<span class="hljs-string">{ResultTemplate}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Pagination</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">InstantSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>and the following is how your application should appear:</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154147895-202befe9-0803-4123-93f4-622db5bb05cd.png" alt="image" /></p>
<p>Finally, using the same procedures as before, we can add sorting capabilities to the application: Add the <code>items</code> with the label default with the value <code>animes</code> to the <code>SortBy</code> widget/component from <code>react-instantsearch-dom</code>, and then create another label called <code>ranked (asc)</code> with the value <code>animes/sort/popularity:asc</code>, and another label called <code>ranked (desc)</code> with the value <code>animes/sort/popularity:desc</code>.</p>
<pre><code class="lang-jsx">&lt;SortBy
  items={[
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Default"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"animes"</span> },
    {
      <span class="hljs-attr">label</span>: <span class="hljs-string">"ranked (asc)"</span>,
      <span class="hljs-attr">value</span>: <span class="hljs-string">"animes/sort/popularity:asc"</span>,
    },
    {
      <span class="hljs-attr">label</span>: <span class="hljs-string">"ranked (desc)"</span>,
      <span class="hljs-attr">value</span>: <span class="hljs-string">"animes/sort/popularity:desc"</span>,
    },
  ]}
  defaultRefinement=<span class="hljs-string">"animes"</span>
/&gt;
</code></pre>
<p>Finally, let's update the template for the information we want to display in our app (for example, title,img_url and genres), so this is how your code should appear.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ResultTemplate</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> ResultTemplate = <span class="hljs-function">(<span class="hljs-params">{ hit }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-wrapper"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{hit.link}</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-image"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{hit.img_url}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"movie"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{hit.link}</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-title"</span>&gt;</span>{hit.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"anime-genre"</span>&gt;</span>Genres: {hit.genre}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{hit.synopsis}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ResultTemplate;
</code></pre>
<p>Add a few more styles to the project to make it appear even better, so the application's styles should look like this.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* App.css */</span>
<span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600&amp;family=Poppins:ital,wght@0,100;0,200;0,300;1,100;1,200&amp;display=swap"</span>);
* {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Poppins"</span>, sans-serif;
}
<span class="hljs-selector-class">.super-title</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.search-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-class">.results-section</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">5rem</span>;
  <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">5rem</span>;
}

<span class="hljs-selector-class">.anime-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.anime-wrapper</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.anime-image</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
}

<span class="hljs-selector-class">.searchbox-gap</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-class">.ais-Hits-list</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, minmax(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:link</span>,
<span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:visited</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">display</span>: inline-block;
}
</code></pre>
<p>Finally, use the react instantsearch library's <code>instantsearch.css</code> style and add it directly to the project. Hence, after you've integrated everything, your complete project's source code should look like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">import</span> TypesenseInstantSearchAdapter <span class="hljs-keyword">from</span> <span class="hljs-string">"typesense-instantsearch-adapter"</span>;
<span class="hljs-keyword">import</span> ResultTemplate <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ResultTemplate"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> {
  InstantSearch,
  SearchBox,
  Hits,
  Configure,
  Pagination,
  SortBy,
  Panel,
  RefinementList,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-instantsearch-dom"</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"instantsearch.css/themes/satellite.css"</span>;

<span class="hljs-keyword">const</span> typesenseInstantsearchAdapter = <span class="hljs-keyword">new</span> TypesenseInstantSearchAdapter({
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"animesearch"</span>,
    <span class="hljs-attr">nodes</span>: [
      {
        <span class="hljs-attr">host</span>: <span class="hljs-string">"localhost"</span>,
        <span class="hljs-attr">port</span>: <span class="hljs-string">"8108"</span>,
        <span class="hljs-attr">protocol</span>: <span class="hljs-string">"http"</span>,
      },
    ],
  },
  <span class="hljs-attr">additionalSearchParameters</span>: {
    <span class="hljs-attr">queryBy</span>: <span class="hljs-string">"title,synopsis,genre"</span>,
    <span class="hljs-attr">queryByWeights</span>: <span class="hljs-string">"4,2,1"</span>,
    <span class="hljs-attr">numTypos</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">typoTokensThreshold</span>: <span class="hljs-number">1</span>,
  },
});

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"super-title"</span>&gt;</span>
        👊🏻👨🏻‍🦲Anime search application built using react👺🔪👿
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">InstantSearch</span>
        <span class="hljs-attr">indexName</span>=<span class="hljs-string">"animes"</span>
        <span class="hljs-attr">searchClient</span>=<span class="hljs-string">{typesenseInstantsearchAdapter.searchClient}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Configure</span> <span class="hljs-attr">hitsPerPage</span>=<span class="hljs-string">{12}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"search-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">aside</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"results-section"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Popularity"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">SortBy</span>
                <span class="hljs-attr">items</span>=<span class="hljs-string">{[</span>
                  { <span class="hljs-attr">label:</span> "<span class="hljs-attr">Default</span>", <span class="hljs-attr">value:</span> "<span class="hljs-attr">animes</span>" },
                  {
                    <span class="hljs-attr">label:</span> "<span class="hljs-attr">ranked</span> (<span class="hljs-attr">asc</span>)",
                    <span class="hljs-attr">value:</span> "<span class="hljs-attr">animes</span>/<span class="hljs-attr">sort</span>/<span class="hljs-attr">popularity:asc</span>",
                  },
                  {
                    <span class="hljs-attr">label:</span> "<span class="hljs-attr">ranked</span> (<span class="hljs-attr">desc</span>)",
                    <span class="hljs-attr">value:</span> "<span class="hljs-attr">animes</span>/<span class="hljs-attr">sort</span>/<span class="hljs-attr">popularity:desc</span>",
                  },
                ]}
                <span class="hljs-attr">defaultRefinement</span>=<span class="hljs-string">"animes"</span>
              /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Genre"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">RefinementList</span>
                <span class="hljs-attr">attribute</span>=<span class="hljs-string">"genre"</span>
                <span class="hljs-attr">transformItems</span>=<span class="hljs-string">{(items)</span> =&gt;</span>
                  items.map((item) =&gt; ({
                    ...item,
                    label: item.label.slice(2, -2),
                  }))
                }
                searchable={true}
                showMore={true}
                limit={10}
                showMoreText="Show more"
                showLessText="Show less"
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">header</span>=<span class="hljs-string">"Aired"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">RefinementList</span> <span class="hljs-attr">attribute</span>=<span class="hljs-string">"aired"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"searchbox-gap"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Hits</span> <span class="hljs-attr">hitComponent</span>=<span class="hljs-string">{ResultTemplate}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Pagination</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">InstantSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Let's take a look at the final version of our typesense-integrated Anime search application.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154140579-f5d104b6-65cc-4b71-bd5a-9f7d8158771a.png" alt="Final" /></p>
<p>Entire source code of the application can be found <a target="_blank" href="https://github.com/aviyelverse/Article-project-demo/tree/main/anime-searchapp-reactjs-typesense">here</a></p>
<p>Join Aviyel’s community to learn more about the open source project, get tips on how to contribute, and join active dev groups. Aviyel is a collaborative platform that assists open source project communities in monetizing and long-term sustainability. To know more visit <a target="_blank" href="https://aviyel.com/discussions">Aviyel.com</a> and find great blogs and events, just like this one! Sign up now for early access, and don’t forget to follow us on our socials!</p>
<p>Follow <a target="_blank" href="https://bit.ly/3wOHnpV">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions?utm_source=dev_to&amp;utm_medium=page_main&amp;utm_campaign=devto_article">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Join Aviyel's Discord =&gt; <a target="_blank" href="https://discord.gg/TbfZmbvnN5">Aviyel's world</a></p>
<p>Twitter =&gt;<a target="_blank" href="https://bit.ly/3wOHnpV">https://twitter.com/AviyelHq</a></p>
]]></content:encoded></item><item><title><![CDATA[Fullstack eCommerce site using Nextjs, Supabase, Prisma and chatwoot.]]></title><description><![CDATA[In this article tutorial, we will be building SuperbaseEcommerce full-stack application. This application is simply an online eCommerce shopping site where users can browse all of the products, upload their own products, and even purchase the product...]]></description><link>https://pramitmarattha.com.np/fullstack-ecommerce-site-using-nextjs-supabase-prisma-and-chatwoot</link><guid isPermaLink="true">https://pramitmarattha.com.np/fullstack-ecommerce-site-using-nextjs-supabase-prisma-and-chatwoot</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[ecommerce]]></category><category><![CDATA[fullstack]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[THW Web Apps]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Sun, 01 May 2022 09:36:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1651397573475/XUQvlFj67.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article tutorial, we will be building <code>SuperbaseEcommerce</code> full-stack application. This application is simply an online eCommerce shopping site where users can browse all of the products, upload their own products, and even purchase the products(<code>This functionality will be added in the next series of articles</code>). It is similar to an Amazon app, but it is simpler because we will not implement any actual payment or shipping procedures. Here's a live demonstration of the final version of the app. This is how your app should look after you finish this tutorial. Feel free to experiment with it to get a sense of all the features we will be implementing.</p>
<h3 id="heading-live-demo-andgt-httpssupabase-ecommercevercelapphttpssupabase-ecommercevercelapp">Live Demo =&gt; <a target="_blank" href="https://supabase-ecommerce.vercel.app">https://supabase-ecommerce.vercel.app</a></h3>
<p>
<img src="https://user-images.githubusercontent.com/37651620/158058874-6a86646c-c60e-4c39-bc6a-d81974afe635.png" alt="Supabase Ecommerce logo" />
</p>

<p><img src="https://user-images.githubusercontent.com/37651620/159170940-d8c210c4-5b9d-47f7-b5d8-547bea3106fc.png" alt="Demo" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159170944-b48ead6f-6482-4234-a5ea-7b20335ca7fe.png" alt="Demo" /></p>
<p>So, in this tutorial, we'll learn how to build this full-stack app with <code>Next.js</code>, the react framework, <code>NextAuth.js</code>, for implementing passwordless and OAuth authentication, <code>Supabase</code>, for persisting app data into a PostgreSQL database and stashing media files and information, and <code>Prisma</code>, for making it simple to read and write data from and to the database from our app.</p>
<p>This article tutorial covers many topics and technical concepts necessary to build a modern full-stack app, even if this app is a simplified version of a more advanced ecommerce site like Amazon. You should be able to use all of the technologies covered in this tutorial, including react, nextjs, prisma, supabase, and others, but most importantly, you should be able to build any full-stack app using those technologies. You'll go at your own speed and intensity, with us guiding you along the way. After completing this guide, the goal of this article is to provide you with the tools and techniques you'll need to build a similar app on your own.To put it another way, this tutorial will not only teach you how to use those technologies in great detail, but it will also provide you with the proper mixture of principles and application to help you grasp all of the key concepts so that you can proudly build your own apps from scratch later part on this article.</p>
<p>Let's start with the react portion and build our application. The first step is to install Node.js if it isn't already on your computer. So, go to the official Node.js website and download the most recent version. Node js is required to use the node package manager, abbreviated as npm. Now launch your preferred code editor and navigate to the folder. For this article tutorial, we'll be using the VScode code editor.</p>
<h3 id="heading-setting-up-supabaseecommerce-project">Setting up SupabaseEcommerce project.</h3>
<p>There is a <a target="_blank" href="https://github.com/pramit-marattha/SupabaseEcommerce">Github repository</a> dedicated to this project, which consists of three branches. Clone the <a target="_blank" href="https://github.com/pramit-marattha/SupabaseEcommerce/tree/SupabaseEcommerce-starter"><code>SupabaseEcommerce-starter</code></a> branch to get started.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/158067824-de726446-b049-4ebb-9c2f-adbecd571d64.png" alt="Github" /></p>
<p>The <code>Main</code> branch contains the entire <code>final</code> source code of the application, so clone the <code>SupabaseEcommerce-starter</code> branch if you want to follow along with this tutorial.</p>
<pre><code>git clone <span class="hljs-operator">-</span><span class="hljs-operator">-</span>branch SupabaseEcommerce<span class="hljs-operator">-</span>starter https:<span class="hljs-comment">//github.com/pramit-marattha/SupabaseEcommerce.git</span>
</code></pre><p>After that, head over to the cloned directory and install the dependencies before starting the <code>Next.js</code> development server:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> SupabaseEcommerce
yarn add all
yarn dev
</code></pre>
<p>You can now check if everything is working properly by going to <code>http://localhost:3000</code> and editing <code>pages/index.js</code>, then viewing the updated result in your browser.For more information on how to use <code>create-next-app</code>, you can review the <a target="_blank" href="https://nextjs.org/docs/api-reference/create-next-app">create-next-app documentation</a>.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/158068425-c3087d4a-14fb-46ac-a99c-10cd6412624f.png" alt="Documentation" /></p>
<p>It usually only takes a few minutes to get everything set up. So, for this project we will be using <code>yarn</code> to add packages to a project, which will install and configure everything for us so that we can get started right away with an excellent starter template. It's time to start our development server, so head over to that <code>SupabaseEcommerce</code> folder and type <code>yarn add all</code> and then <code>yarn dev</code> and the browser will instantly open our starter template <code>Next.js</code> appplication.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/158068726-0b8eafe8-6c4d-45eb-98cf-ef64faf58103.png" alt="Demo" /></p>
<p>Your application’s folder structure should look something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160289391-d30f6034-1d08-46f7-b18a-3b90ca8f9c24.png" alt="Folder structure" /></p>
<p>So you might be curious about the source of the content. Remember that all of our source code is housed in the pages folder, and react/next will inject it into the root div element. Let’s take a look at our pages folder, which contains some javascript files and one API folder.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/158071549-8daff075-bf73-4873-96ca-ab3cd473848d.png" alt="Pages" /></p>
<p>Before we dive any further lets actually create a landing page for our site.</p>
<p>so before we even begin first you need to install <code>framer-motion</code> library.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/158306049-86478da8-4e06-473d-bfec-493196a228de.png" alt="Framer Motion" /></p>
<p>Let's dive in and create a beautiful looking UI for our E-commerce application before we start on the backend integration part. Let's start by making a landing page for the app, and then move on to making a product page for it. So, inside the <code>components</code> folder, create a <code>Layout</code> component and add the following code to it. This component is simply a basic layout for our application that includes a navigation bar &amp; menus as well as the functionality to display our application's registration/login modal.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/Layout.js</span>
<span class="hljs-keyword">import</span> { Fragment, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"prop-types"</span>;
<span class="hljs-keyword">import</span> AuthModal <span class="hljs-keyword">from</span> <span class="hljs-string">"./AuthModal"</span>;
<span class="hljs-keyword">import</span> { Menu, Transition } <span class="hljs-keyword">from</span> <span class="hljs-string">"@headlessui/react"</span>;
<span class="hljs-keyword">import</span> {
  HeartIcon,
  HomeIcon,
  LogoutIcon,
  PlusIcon,
  UserIcon,
  ShoppingCartIcon,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/outline"</span>;
<span class="hljs-keyword">import</span> { ChevronDownIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/solid"</span>;

<span class="hljs-keyword">const</span> menuItems = [
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">"List a new home"</span>,
    <span class="hljs-attr">icon</span>: PlusIcon,
    <span class="hljs-attr">href</span>: <span class="hljs-string">"/list"</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">"My homes"</span>,
    <span class="hljs-attr">icon</span>: HomeIcon,
    <span class="hljs-attr">href</span>: <span class="hljs-string">"/homes"</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">"Favorites"</span>,
    <span class="hljs-attr">icon</span>: HeartIcon,
    <span class="hljs-attr">href</span>: <span class="hljs-string">"/favorites"</span>,
  },
  {
    <span class="hljs-attr">label</span>: <span class="hljs-string">"Logout"</span>,
    <span class="hljs-attr">icon</span>: LogoutIcon,
    <span class="hljs-attr">onClick</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>,
  },
];

<span class="hljs-keyword">const</span> Layout = <span class="hljs-function">(<span class="hljs-params">{ children = <span class="hljs-literal">null</span> }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">const</span> [showModal, setShowModal] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> user = <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">const</span> isLoadingUser = <span class="hljs-literal">false</span>;

  <span class="hljs-keyword">const</span> openModal = <span class="hljs-function">() =&gt;</span> setShowModal(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> closeModal = <span class="hljs-function">() =&gt;</span> setShowModal(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>SupaaShop | A new way to shop!<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"SupaaShopp"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen flex flex-col font-['Poppins'] bg-[linear-gradient(90deg, #161122 21px, transparent 1%) center, linear-gradient(#161122 21px, transparent 1%) center, #a799cc]"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-28 w-full shadow-lg"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-full container mx-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-full px-5 flex justify-between items-center space-x-5"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center space-x-1"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"shrink-0 w-24 h-24 text-primary"</span>
                    <span class="hljs-attr">src</span>=<span class="hljs-string">"https://user-images.githubusercontent.com/37651620/158058874-6a86646c-c60e-4c39-bc6a-d81974afe635.png"</span>
                    <span class="hljs-attr">alt</span>=<span class="hljs-string">"Logo"</span>
                  /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold tracking-wide text-white"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl text-success"</span>&gt;</span>S<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>upabase
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl text-success"</span>&gt;</span>E<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>commerce
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center space-x-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/create"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ml-4 px-4 py-5 rounded-md bg-info text-primary hover:bg-primary hover:text-info focus:outline-none focus:ring-4 focus:ring-primaryfocus:ring-opacity-50  font-semibold transition"</span>&gt;</span>
                    Register shop !
                  <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                {isLoadingUser ? (
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h-8 w-[75px] bg-gray-200 animate-pulse rounded-md"</span> /&gt;</span>
                ) : user ? (
                  <span class="hljs-tag">&lt;<span class="hljs-name">Menu</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"div"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative z-50"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center space-x-px group"</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shrink-0 flex items-center justify-center rounded-full overflow-hidden relative bg-gray-200 w-9 h-9"</span>&gt;</span>
                        {user?.image ? (
                          <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
                            <span class="hljs-attr">src</span>=<span class="hljs-string">{user?.image}</span>
                            <span class="hljs-attr">alt</span>=<span class="hljs-string">{user?.name</span> || "<span class="hljs-attr">Avatar</span>"}
                            <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
                          /&gt;</span>
                        ) : (
                          <span class="hljs-tag">&lt;<span class="hljs-name">UserIcon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-400 w-6 h-6"</span> /&gt;</span>
                        )}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">ChevronDownIcon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 shrink-0 text-gray-500 group-hover:text-current"</span> /&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Button</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">Transition</span>
                      <span class="hljs-attr">as</span>=<span class="hljs-string">{Fragment}</span>
                      <span class="hljs-attr">enter</span>=<span class="hljs-string">"transition ease-out duration-100"</span>
                      <span class="hljs-attr">enterFrom</span>=<span class="hljs-string">"opacity-0 scale-95"</span>
                      <span class="hljs-attr">enterTo</span>=<span class="hljs-string">"opacity-100 scale-100"</span>
                      <span class="hljs-attr">leave</span>=<span class="hljs-string">"transition ease-in duration-75"</span>
                      <span class="hljs-attr">leaveFrom</span>=<span class="hljs-string">"opacity-100 scale-100"</span>
                      <span class="hljs-attr">leaveTo</span>=<span class="hljs-string">"opacity-0 scale-95"</span>
                    &gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Items</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute right-0 w-72 overflow-hidden mt-1 divide-y divide-gray-100 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center space-x-2 py-4 px-4 mb-2"</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shrink-0 flex items-center justify-center rounded-full overflow-hidden relative bg-gray-200 w-9 h-9"</span>&gt;</span>
                            {user?.image ? (
                              <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
                                <span class="hljs-attr">src</span>=<span class="hljs-string">{user?.image}</span>
                                <span class="hljs-attr">alt</span>=<span class="hljs-string">{user?.name</span> || "<span class="hljs-attr">Avatar</span>"}
                                <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
                              /&gt;</span>
                            ) : (
                              <span class="hljs-tag">&lt;<span class="hljs-name">UserIcon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-400 w-6 h-6"</span> /&gt;</span>
                            )}
                          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col truncate"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>
                              {user?.email}
                            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2"</span>&gt;</span>
                          {menuItems.map(
                            ({ label, href, onClick, icon: Icon }) =&gt; (
                              <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                                <span class="hljs-attr">key</span>=<span class="hljs-string">{label}</span>
                                <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 last:border-t last:pt-2 last:mt-2"</span>
                              &gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">Menu.Item</span>&gt;</span>
                                  {href ? (
                                    <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{href}</span>&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center space-x-2 py-2 px-4 rounded-md hover:bg-gray-100"</span>&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 shrink-0 text-gray-500"</span> /&gt;</span>
                                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                                      <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                                  ) : (
                                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                                      <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full flex items-center space-x-2 py-2 px-4 rounded-md hover:bg-gray-100"</span>
                                      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>
                                    &gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 shrink-0 text-gray-500"</span> /&gt;</span>
                                      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                                  )}
                                <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Item</span>&gt;</span>
                              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                            )
                          )}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">Menu.Items</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">Transition</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">Menu</span>&gt;</span>
                ) : (
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{openModal}</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"ml-4 px-4 py-5 rounded-md bg-info hover:bg-primary focus:outline-none focus:ring-4 focus:ring-primary focus:ring-opacity-50 text-primary hover:text-info font-extrabold transition"</span>
                  &gt;</span>
                    Login
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                )}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-grow container mx-auto"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-4 py-12"</span>&gt;</span>
            {typeof children === "function" ? children(openModal) : children}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">AuthModal</span> <span class="hljs-attr">show</span>=<span class="hljs-string">{showModal}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{closeModal}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

Layout.propTypes = {
  <span class="hljs-attr">children</span>: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Layout;
</code></pre>
<p>Let's create a 'Hero' section of our landing page after you've successfully created a layout for the application. To do so, simply paste the following code into that section. So, in this section, we'll add an image on the right, a large text heading, and two buttons on the left.Note that we are styling our project with the absolute power of <code>tailwind css</code> and <code>framer-motion</code> to add some beautiful transition animation to the image .Since we've already created buttons on our starter template, you won't have to worry about creating them from scratch; instead, you can simply import them from the components and use them.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/Hero.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> PrimaryButton <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/PrimaryButton"</span>;
<span class="hljs-keyword">import</span> SecondaryButton <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/SecondaryButton"</span>;
<span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;

<span class="hljs-keyword">const</span> Hero = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-6xl mx-auto py-12 flex flex-col md:flex-row space-y-8 md:space-y-0"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full md:w-1/2 flex flex-col justify-center items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-xs lg:max-w-md space-y-10 w-5/6 mx-auto md:w-full text-center md:text-left"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-primary font-extrabold text-white text-3xl sm:text-4xl md:text-5xl md:leading-tight"</span>&gt;</span>
            Shop <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-success"</span>&gt;</span>whenever<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> and{" "}
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-success"</span>&gt;</span>however<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> you want from,{" "}
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-success"</span>&gt;</span>wherever<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> you are..{" "}
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-secondary text-gray-500 text-base md:text-lg lg:text-xl"</span>&gt;</span>
            SuperbaseEcommerce improves and streamlines your shopping
            experience..
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex space-x-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">PrimaryButton</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"Register"</span> <span class="hljs-attr">link</span>=<span class="hljs-string">"/"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">SecondaryButton</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"Let's Shop!"</span> <span class="hljs-attr">link</span>=<span class="hljs-string">"/products"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full md:w-1/2 transform scale-x-125 lg:scale-x-100"</span>
        <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">60</span> }}
        <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">1</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.8</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">0</span> }}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">alt</span>=<span class="hljs-string">"hero-img"</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/shop.svg"</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"mx-auto object-cover shadow rounded-tr-extraLarge rounded-bl-extraLarge w-full h-96 sm:h-112 md:h-120"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Hero;
</code></pre>
<p>Now, before re-running the server, import this <code>Hero</code> component into the <code>index.js</code> file and wrap it in the Layout component to see the changes you've made.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Hero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Hero"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Hero</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>This is how your landing page should appear.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159169803-0d0ed5ff-0084-45d8-b2b9-f802d4e69d2b.png" alt="Demo" /></p>
<p>After you've finished with the <code>Hero</code> section, go ahead and create a <code>ShopCards</code> component, where we'll simply list the demo features that this application offers and add some images, so your final code for the <code>ShopCards</code> component should look like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/ShopCards.js</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;

<span class="hljs-keyword">const</span> ShopCards = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [tab, setTab] = useState(<span class="hljs-number">1</span>);

  <span class="hljs-keyword">const</span> tabs = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> heightFix = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (tabs.current.children[tab]) {
      tabs.current.style.height =
        tabs.current.children[tab - <span class="hljs-number">1</span>].offsetHeight + <span class="hljs-string">"px"</span>;
    }
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    heightFix();
  }, [tab]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute inset-0 pointer-events-none pb-26"</span>
        <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
      &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative max-w-6xl mx-auto px-4 sm:px-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"pt-12 md:pt-20"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-3xl mx-auto text-center pb-12 md:pb-16"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl mb-4"</span>&gt;</span>Features<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl text-gray-500"</span>&gt;</span>
              List of features that SuperbaseEcommerce provides.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative max-w-6xl mx-auto px-4 sm:px-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"pt-12 md:pt-20"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-3xl mx-auto text-center pb-6 md:pb-16"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span> <span class="hljs-attr">data-aos</span>=<span class="hljs-string">"zoom-y-out"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{tabs}</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"relative w-full h-full"</span>
                    <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">60</span> }}
                    <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">1</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">0</span> }}
                    <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.8</span>, <span class="hljs-attr">translateY:</span> <span class="hljs-attr">0</span> }}
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                      <span class="hljs-attr">alt</span>=<span class="hljs-string">"hero-img"</span>
                      <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/webShop.svg"</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"mx-auto object-cover shadow rounded-tr-extraLarge rounded-bl-extraLarge w-full h-96 sm:h-112 md:h-120"</span>
                    /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-6xl mx-auto py-12 flex flex-col md:flex-row space-y-8 md:space-y-0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-xl md:max-w-none md:w-full mx-auto md:col-span-7 lg:col-span-6 md:mt-6 pr-12"</span>
              <span class="hljs-attr">data-aos</span>=<span class="hljs-string">"fade-right"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:pr-4 lg:pr-12 xl:pr-16 mb-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"h3 mb-3"</span>&gt;</span>All of our awesome features<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl text-black"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-8 md:mb-0"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">text-lg</span> <span class="hljs-attr">p-5</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">border</span> <span class="hljs-attr">transition</span> <span class="hljs-attr">duration-300</span> <span class="hljs-attr">ease-in-out</span> <span class="hljs-attr">mb-3</span> ${
                    <span class="hljs-attr">tab</span> !== <span class="hljs-string">1</span>
                      ? "<span class="hljs-attr">bg-white</span> <span class="hljs-attr">shadow-md</span> <span class="hljs-attr">border-success</span> <span class="hljs-attr">hover:shadow-lg</span>"
                      <span class="hljs-attr">:</span> "<span class="hljs-attr">bg-success</span> <span class="hljs-attr">border-transparent</span>"
                  }`}
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#0"</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    e.preventDefault();
                    setTab(1);
                  }}
                &gt;
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold leading-snug tracking-tight mb-1 text-gray-600"</span>&gt;</span>
                      Register/Login Feature
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>
                      User can login and save their products for later purchase.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">text-lg</span> <span class="hljs-attr">p-5</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">border</span> <span class="hljs-attr">transition</span> <span class="hljs-attr">duration-300</span> <span class="hljs-attr">ease-in-out</span> <span class="hljs-attr">mb-3</span> ${
                    <span class="hljs-attr">tab</span> !== <span class="hljs-string">2</span>
                      ? "<span class="hljs-attr">bg-white</span> <span class="hljs-attr">shadow-md</span> <span class="hljs-attr">border-purple-200</span> <span class="hljs-attr">hover:shadow-lg</span>"
                      <span class="hljs-attr">:</span> "<span class="hljs-attr">bg-success</span> <span class="hljs-attr">border-transparent</span>"
                  }`}
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#0"</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    e.preventDefault();
                    setTab(2);
                  }}
                &gt;
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold leading-snug tracking-tight mb-1 text-gray-600"</span>&gt;</span>
                      Add to cart
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>
                      User can add the products/items to their cart
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">text-lg</span> <span class="hljs-attr">p-5</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">border</span> <span class="hljs-attr">transition</span> <span class="hljs-attr">duration-300</span> <span class="hljs-attr">ease-in-out</span> <span class="hljs-attr">mb-3</span> ${
                    <span class="hljs-attr">tab</span> !== <span class="hljs-string">3</span>
                      ? "<span class="hljs-attr">bg-white</span> <span class="hljs-attr">shadow-md</span> <span class="hljs-attr">border-purple-200</span> <span class="hljs-attr">hover:shadow-lg</span>"
                      <span class="hljs-attr">:</span> "<span class="hljs-attr">bg-success</span> <span class="hljs-attr">border-transparent</span>"
                  }`}
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#0"</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    e.preventDefault();
                    setTab(3);
                  }}
                &gt;
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold leading-snug tracking-tight mb-1 text-gray-600"</span>&gt;</span>
                      Security
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>
                      Hassle free secure login and registration process.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">text-lg</span> <span class="hljs-attr">p-5</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">border</span> <span class="hljs-attr">transition</span> <span class="hljs-attr">duration-300</span> <span class="hljs-attr">ease-in-out</span> <span class="hljs-attr">mb-3</span> ${
                    <span class="hljs-attr">tab</span> !== <span class="hljs-string">4</span>
                      ? "<span class="hljs-attr">bg-white</span> <span class="hljs-attr">shadow-md</span> <span class="hljs-attr">border-purple-200</span> <span class="hljs-attr">hover:shadow-lg</span>"
                      <span class="hljs-attr">:</span> "<span class="hljs-attr">bg-success</span> <span class="hljs-attr">border-transparent</span>"
                  }`}
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#0"</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    e.preventDefault();
                    setTab(4);
                  }}
                &gt;
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold leading-snug tracking-tight mb-1 text-gray-600"</span>&gt;</span>
                      Personalized shops
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>
                      User can create/register their very own shop and add their
                      own products.
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ShopCards;
</code></pre>
<p>Again, before re-running the server, import this <code>ShopCards</code> component into the <code>index.js</code> file and wrap it in the <code>Layout</code> component &amp; below the <code>Hero</code> component to see the changes you've made.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Hero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Hero"</span>;
<span class="hljs-keyword">import</span> ShopCards <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ShopCards"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Hero</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ShopCards</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>For the time being, this is how your landing page should appear.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159170136-4c2d9b7e-dc6a-4f7d-b897-bee33ac7f338.png" alt="Demo" /></p>
<p>Finally, let's add a Footer section, so make a <code>Footer</code> component and paste the code below into it.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// components/Footer.js</span>
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

<span class="hljs-keyword">const</span> Footer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-6xl mx-auto px-4 sm:px-6 pt-10"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sm:col-span-6 md:col-span-3 lg:col-span-3"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-6xl mx-auto px-4 sm:px-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"pb-12 md:pb-20"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"relative bg-success rounded py-10 px-8 md:py-16 md:px-12 shadow-2xl overflow-hidden"</span>
                  <span class="hljs-attr">data-aos</span>=<span class="hljs-string">"zoom-y-out"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute right-0 bottom-0 pointer-events-none hidden lg:block"</span>
                    <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
                  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex flex-col lg:flex-row justify-between items-center"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center lg:text-left lg:max-w-xl"</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-3xl font-medium mb-2"</span>&gt;</span>
                        Sign-up for the early access!{" "}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-100 text-lg mb-6"</span>&gt;</span>
                        SuperbaseEcommerce improves and streamlines your
                        shopping experience.. !
                      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full lg:w-auto"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row justify-center max-w-xs mx-auto sm:max-w-xl lg:mx-0"</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full appearance-none bg-purple-100 border border-gray-700 focus:border-gray-600 rounded-sm px-4 py-3 mb-2 sm:mb-0 sm:mr-2 text-black placeholder-gray-500"</span>
                            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email…"</span>
                            <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Enter your email…"</span>
                          /&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"btn text-white bg-info hover:bg-success shadow"</span>
                            <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                          &gt;</span>
                            Sign-Up!
                          <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:flex md:items-center md:justify-between py-4 md:py-8 border-t-2 border-solid"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex mb-4 md:order-1 md:ml-4 md:mb-0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center items-center text-blue-400 hover:text-gray-900 bg-blue-100 hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out"</span>
                <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Twitter"</span>
              &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"w-8 h-8 fill-current "</span>
                  <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 32 32"</span>
                  <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M24 11.5c-.6.3-1.2.4-1.9.5.7-.4 1.2-1 1.4-1.8-.6.4-1.3.6-2.1.8-.6-.6-1.5-1-2.4-1-1.7 0-3.2 1.5-3.2 3.3 0 .3 0 .5.1.7-2.7-.1-5.2-1.4-6.8-3.4-.3.5-.4 1-.4 1.7 0 1.1.6 2.1 1.5 2.7-.5 0-1-.2-1.5-.4 0 1.6 1.1 2.9 2.6 3.2-.3.1-.6.1-.9.1-.2 0-.4 0-.6-.1.4 1.3 1.6 2.3 3.1 2.3-1.1.9-2.5 1.4-4.1 1.4H8c1.5.9 3.2 1.5 5 1.5 6 0 9.3-5 9.3-9.3v-.4c.7-.5 1.3-1.1 1.7-1.8z"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ml-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center items-center text-white hover:text-gray-900 bg-black hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out"</span>
                <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Github"</span>
              &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"w-8 h-8 fill-current"</span>
                  <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 32 32"</span>
                  <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M16 8.2c-4.4 0-8 3.6-8 8 0 3.5 2.3 6.5 5.5 7.6.4.1.5-.2.5-.4V22c-2.2.5-2.7-1-2.7-1-.4-.9-.9-1.2-.9-1.2-.7-.5.1-.5.1-.5.8.1 1.2.8 1.2.8.7 1.3 1.9.9 2.3.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8.6-.2 1.3-.3 2-.3s1.4.1 2 .3c1.5-1 2.2-.8 2.2-.8.4 1.1.2 1.9.1 2.1.5.6.8 1.3.8 2.1 0 3.1-1.9 3.7-3.7 3.9.3.4.6.9.6 1.6v2.2c0 .2.1.5.6.4 3.2-1.1 5.5-4.1 5.5-7.6-.1-4.4-3.7-8-8.1-8z"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-shrink-0 mr-2"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"SuperbaseEcommerce"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"object-cover h-20 w-full"</span>
                <span class="hljs-attr">src</span>=<span class="hljs-string">"https://user-images.githubusercontent.com/37651620/159121520-fe42bbf1-a2af-4baf-bdd8-7efad8523202.png"</span>
                <span class="hljs-attr">alt</span>=<span class="hljs-string">"SupabaseEcommerce"</span>
              /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Footer;
</code></pre>
<blockquote>
<p>Note: Again, before re-running the server, import this <code>Footer</code> component into the <code>index.js</code> file and wrap it in the <code>Layout</code> component &amp; below the <code>ShopCards</code> component to see the changes you've made.</p>
</blockquote>
<pre><code class="lang-jsx"><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Hero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Hero"</span>;
<span class="hljs-keyword">import</span> ShopCards <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ShopCards"</span>;
<span class="hljs-keyword">import</span> Footer <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Footer"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Hero</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ShopCards</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Footer</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>So, if you re-run the server, this is what your application should look like.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159170273-6b13b471-5d96-4e7e-88f4-9551edc253b6.png" alt="Demo Footer" /></p>
<p>The structure of your component folders should resemble something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159170780-1308379d-4532-4d9f-b2d7-f069b9564eac.png" alt="Demo" /></p>
<p>Congratulationss!! Now that you've successfully created a landing page for the application, let's move on to the core of the matter: creating the product section of the application.</p>
<p>So, Now let’s look at the <code>_app.js</code> file.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// _app.js</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;
<span class="hljs-keyword">import</span> { Toaster } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p>The App component is used by <code>Next.js</code> to create pages. You can control the page initialization by simply overriding it. It allows you to do amazing things like: <code>Persisting layout across page changes</code>, <code>Keeping state while navigating pages</code>, <code>Custom error handling using componentDidCatch</code>,<code>Inject additional data into pages and Add global styles/CSS</code> are just a few of the great things you can accomplish with it.</p>
<p>In the above <code>\_app.js</code> code the Component parameter represents the active page, when you switch routes, Component will change to the new page. As a result, the page will receive any props you pass to Component. Meanwhile <code>pageProps</code> is an empty object that contains the initial props that were preloaded for your page by one of the data fetching methods.</p>
<p>Now, inside the <code>pages</code> folder, create a new page called <code>products.js</code> and import the <code>Layout</code> and <code>Grid</code> components, then import the <code>data.json</code> file as products and make the following changes to it.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/products.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Grid"</span>;

<span class="hljs-keyword">import</span> products <span class="hljs-keyword">from</span> <span class="hljs-string">"data.json"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 p-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">products</span>=<span class="hljs-string">{products}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-database-configurations">Database Configurations</h2>
<p>Before jumping directly on our application, we'll be utilizing the power of <code>Supabase</code> to create a <code>PostgreSQL</code> database, the <code>Prisma schema</code> to define the app data model, and Next.js to connect those two together. So, let's get started building our database.</p>
<h3 id="heading-supabase-configurartion">Supabase Configurartion</h3>
<p>Creating a PostgreSQL database in Supabase is as simple as starting a new project. Head over to <a target="_blank" href="https://supabase.com/">supabase.com</a> and <code>Sign-in</code> to your account.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159206560-3b46e8b2-ded2-4146-97e3-4a640b72c8b7.png" alt="Supabase" /></p>
<p>After you've successfully signed in, you should see something similar to this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159206701-23d739cc-37d7-47b6-bf39-63c4e04c3400.png" alt="New project" /></p>
<p>Now, select <code>New project</code> button. Fill in your project's required details and again click <code>Create Project</code> button and wait for the new database to load.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159207037-87f64dbe-baf6-45b3-81c5-c9c9d9dd65c3.png" alt="Create Project" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159207145-ef6283f0-96b2-4e24-b537-a449c8c2f8b5.png" alt="Creating project" /></p>
<p>After the supabase configured the project, your dashboard should look something similar to this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159207301-ba504656-531f-4782-a806-25b9d6169322.png" alt="SupabaseDashboard" /></p>
<h3 id="heading-creating-a-connection-url">Creating a connection URL</h3>
<p>Follow the steps outlined below to retrieve your database connection URL after your database has been successfully created. We'll need it to use Prisma in our Next.js app to query and create data.</p>
<ul>
<li><strong>Step1</strong> : Head over to the <code>Settings tab</code>(Located at the left side)</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/159232832-0ecb374c-1185-464d-b1ba-99b82c650119.png" alt="Setting Tab" /></p>
<ul>
<li><strong>Step2</strong> : Click the <code>Database</code> tab in the sidebar (Located on the left side)</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/159232570-299da821-d7ec-4b35-bef8-7f6b55a86327.png" alt="Database" /></p>
<ul>
<li><strong>Step3</strong> : Head over to the bottom of the page to find the <code>Connection string</code> section, then select <code>Nodejs</code> and copy the URL.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/159337831-bed01290-cd64-4b48-8afa-a37fc35e2540.png" alt="Connection string" /></p>
<h2 id="heading-initializing-prisma">Initializing Prisma</h2>
<p>Prisma is a next-generation ORM that can be used in Node.js and TypeScript applications to access a database. W eare going to use prisma fo our application because it includes all of the code we need to run our queries. It will save us a lot of time and keep us from having to write a bunch of boilerplate codes.</p>
<h3 id="heading-installing-prisma">Installing prisma</h3>
<h4 id="heading-prisma-cli-installation">Prisma CLI installation</h4>
<p>The Prisma command line interface (CLI) is the primary command-line interface for interacting with your Prisma project. It can create new project assets, generate Prisma Client, and analyze existing database structures via introspection to create your application models automatically.</p>
<pre><code><span class="hljs-built_in">npm</span> i prisma
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159416387-5caea0cc-d44b-4cb4-ba9d-7cc2b02a086c.png" alt="Prisma Installation" /></p>
<h4 id="heading-initialize-prisma">Initialize prisma</h4>
<p>Once you've installed the Prisma CLI, run the following command to get <code>Prisma</code> started in your <code>Next.js</code> application. It will then create a <code>/prisma</code> directory and the <code>schema.prisma</code> file within it inside your particular project folder. so, inside it we will be adding all the configuration for our application.</p>
<pre><code>npx prisma <span class="hljs-keyword">init</span>
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159417419-f3dbe24b-0041-4306-be72-9090142d5bc3.png" alt="prismaSchema" /></p>
<pre><code class="lang-js"><span class="hljs-comment">// prisma.schema</span>
generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}
</code></pre>
<blockquote>
<p>Note: schema.prisma uses Prisma Schema Language(PSL)</p>
</blockquote>
<p><code>Prisma-client-js</code>, the Prisma JavaScript client, is the configured client represented by the <code>generator</code> block.</p>
<pre><code class="lang-js">generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}
</code></pre>
<p>Next one is the the provider property of this block represents the type of database we want to use, and the connection url represents how Prisma connects to it.</p>
<pre><code class="lang-js">datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}
</code></pre>
<h3 id="heading-environment-variable">Environment variable</h3>
<p>Using environment variables in the schema allows you to keep secrets out of the schema file which in turn improves the portability of the schema by allowing you to use it in different environments. Environment variables is created automatically after we fire the <code>npx prisma init</code> command.</p>
<blockquote>
<p>Note: Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview).</p>
</blockquote>
<pre><code><span class="hljs-attr">DATABASE_URL</span>=<span class="hljs-string">"postgresql://test:test@localhost:5432/test?schema=foo"</span>
</code></pre><p>As you can see, there is an <code>DATABASE_URL</code> variable with a dummy connection URL in this environment variable <code>.env</code>. So, replace this value with the connection string you obtained from Supabase.</p>
<pre><code><span class="hljs-attr">DATABASE_URL</span>=<span class="hljs-string">"postgresql://postgres:[YOUR-PASSWORD]@db.bboujxbwamqvgypibdkh.supabase.co:5432/postgres"</span>
</code></pre><h3 id="heading-prisma-schemas-and-models">Prisma schemas and models</h3>
<p>We can begin working on our application's data models now that database is finally connected to your <code>Next.js</code>. In Prisma, our application models should be defined within the Prisma schema using the Prisma models. These models represent the entities of our application and are defined by the model blocks in the <code>schema.prisma</code> file. Each block contains several fields that represent the data for each entity. So, let's begin by creating the <code>Product</code> model, which will define the data schema for our products properties.</p>
<h4 id="heading-defining-models">Defining models</h4>
<p>Models represent the entities of your application domain. Models are represented by model blocks and define a number of fields. In this data model, <code>Product</code> is the model.</p>
<pre><code class="lang-js"><span class="hljs-comment">// prisma.schema</span>
generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}

model Product {
  id          <span class="hljs-built_in">String</span>   @id @<span class="hljs-keyword">default</span>(cuid())
  image       <span class="hljs-built_in">String</span>?
  title       <span class="hljs-built_in">String</span>
  description <span class="hljs-built_in">String</span>
  status      <span class="hljs-built_in">String</span>?
  price       Float
  authenticity        Int?
  returnPolicy        Int?
  warranty       Int?
  createdAt   DateTime @<span class="hljs-keyword">default</span>(now())
  updatedAt   DateTime @updatedAt
}
</code></pre>
<p>Each field, as shown in our Product model, has at least a name and its type. To learn more about the Scalar types and Prisma schema refrences visit the following links .</p>
<ul>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#scalar-fields">Data model</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-schema">Prisma schema</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#model-fields">Prisma schema reference</a></li>
</ul>
<h4 id="heading-generate-prisma-client">Generate Prisma Client</h4>
<p>After designning Prisma model, we can begin generating our Prisma Client. We'll need to use Prisma's JavaScript library later in the article to interact with our data from within our <code>Next.js</code> app without having to write all of the SQL queries ourselves. But there's more to it. Prisma Client is, in fact, an auto-generated type-safe API designed specifically for our application which will gives us the JavaScript code we need to run queries on our data.</p>
<ul>
<li><p><strong>Step 1</strong>: Installing prisma client</p>
<pre><code><span class="hljs-built_in">npm</span> install @prisma/client
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159432404-3e880b0a-4058-44f9-b922-652e7e389d63.png" alt="PrismaClient" /></p>
</li>
<li><p><strong>step2</strong>: Generating Prisma client</p>
<pre><code><span class="hljs-attribute">npx</span> prisma generate
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159432604-f6586811-262f-4d5f-b79b-5be9c4f1d5ff.png" alt="Prisma Generate" /></p>
</li>
</ul>
<h4 id="heading-the-prismaclient-npm-package">The @prisma/client npm package</h4>
<p>The @prisma/client npm package consists of two key parts:</p>
<ul>
<li>The <code>@prisma/client</code> module itself, which only changes when you re-install the package</li>
<li>The <code>.prisma/client</code> folder, which is the default location for the unique Prisma Client generated from your schema</li>
</ul>
<p><code>@prisma/client/index.d.ts</code> exports <code>.prisma/client</code></p>
<p>Finally, after you have done that inside your <code>./node_modules</code> folder, you should now find the generated Prisma Client code.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159435415-e4765d0e-b5c5-4fc5-9ad2-1ddf381539a4.png" alt="PrismaGenerate" /></p>
<blockquote>
<p>Note: You need to re-run the prisma generate command after every change that's made to your Prisma schema to update the generated Prisma Client code.</p>
</blockquote>
<p>Here is a graphical illustration of the typical workflow for the Prisma Client generation:</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159502666-d8c85d78-02a3-4af0-8f4e-6d29e9193247.png" alt="WorkFlow" /></p>
<blockquote>
<p>Note also that prisma generate is automatically invoked when you're installing the <code>@prisma/client</code> npm package.</p>
</blockquote>
<p>The Prisma Client is generated from the Prisma schema and is unique to your project. Each time you change the schema and run prisma generate, the client code changes itself.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159506561-c361008c-6516-44fe-8d98-07ec4688cc38.png" alt="PrismaClient" /></p>
<p>Pruning in <code>Node.js</code> package managers has no effect on the <code>.prisma</code> folder.</p>
<h2 id="heading-creating-a-table-in-supabase">Creating a table in <code>Supabase</code></h2>
<p>If you look at your database in Supabase, you'll notice there is no table inside it. It's because we haven't yet created the <code>Product</code> table.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159444118-7a373b58-b972-4bb9-9c8b-ddfd274526bd.png" alt="DashBoardScrrenshot" /></p>
<p>The Prisma model we defined in our <code>schema.prisma</code> file has not yet been reflected in our database. As a result, we must manually push changes to our data model to our database.</p>
<h3 id="heading-pushing-the-data-model">Pushing the data model</h3>
<p>Prisma makes it really very easy to synchonize the schema with our database.So to do that follow the command listed below.</p>
<pre><code>npx prisma db <span class="hljs-keyword">push</span>
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159443639-7b95dd91-7a02-4bd1-8603-749ccfa5a0ab.png" alt="PrismaDB Push" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159445495-f28b10b6-7bb1-49d3-a6ab-e044950b51c6.png" alt="PushDatabase" /></p>
<p>This command is only good for prototyping on the schemas locally.</p>
<p>OR,</p>
<pre><code><span class="hljs-attribute">npx</span> prisma migrate dev
</code></pre><p>This method (<code>npx prisma migrate dev</code>) will be used in this article because it is very useful in that it allows us to directly sync our Prisma schema with our database while also allowing us to easily track the changes that we make.</p>
<p>So, to begin using Prisma Migrate, enter the following command into the command prompt and after that enter a name for this first migration when prompted.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159447379-c54179e1-e1d1-4f6b-a8fc-d73059b360c4.png" alt="PrismaMigrate" /></p>
<p>After you have completed this process successfully, prisma will automatically generate SQL database migration files, and you should be able to see the SQL which should look something like this if you look inside the <code>prisma</code> folder.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159448032-a0259fb8-ed70-4275-9676-41f8b6fbc57f.png" alt="FolderStructure" /></p>
<pre><code class="lang-sql"><span class="hljs-comment">-- CreateTable</span>
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">"Product"</span> (
    <span class="hljs-string">"id"</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-string">"image"</span> <span class="hljs-built_in">TEXT</span>,
    <span class="hljs-string">"title"</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-string">"description"</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-string">"status"</span> <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-string">"price"</span> <span class="hljs-keyword">DOUBLE</span> <span class="hljs-keyword">PRECISION</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    <span class="hljs-string">"authenticity"</span> <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-string">"returnPolicy"</span> <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-string">"warranty"</span> <span class="hljs-built_in">INTEGER</span>,
    <span class="hljs-string">"createdAt"</span> <span class="hljs-built_in">TIMESTAMP</span>(<span class="hljs-number">3</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CURRENT_TIMESTAMP</span>,
    <span class="hljs-string">"updatedAt"</span> <span class="hljs-built_in">TIMESTAMP</span>(<span class="hljs-number">3</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,

    <span class="hljs-keyword">CONSTRAINT</span> <span class="hljs-string">"Product_pkey"</span> PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">"id"</span>)
);
<span class="hljs-comment">---</span>
</code></pre>
<p>Finally, check the Supabase dashboard to see if everything has been successfully synced.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159447800-82feed93-398d-4a8a-89c1-fbf10a4adf74.png" alt="Supabase" /></p>
<h2 id="heading-prisma-studio">Prisma Studio</h2>
<p>Prisma Studio is a visual interface to the data residing inside your database where you can use to quickly visualize and manipulate the data. The cool thing about it is that it runs in entirely on your browser and you don't need to set up any connections because it's already comes with the prisma package. Not only that, from the studio, you can quickly open all of your application's models and interact with them directly via. studio itself.</p>
<blockquote>
<p>Note: There is also desktop application available to download</p>
</blockquote>
<h3 id="heading-launching-prisma-studio">Launching Prisma Studio</h3>
<p>Launching the prisma studio is really very easy. Literally all you have to do is run the following command from a Prisma project.</p>
<pre><code><span class="hljs-attribute">npx</span> prisma studio
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/159463409-b9614ad2-5c63-4519-98f2-d2ab791cc604.png" alt="PrismaStudio" /></p>
<p>Now, open your browser and head over to <code>http://localhost:5555/</code>. You should be able to see the single table that we've created previously if you've followed all of the steps correctly.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159463579-2019f826-22c6-484c-a877-319ec6abe170.png" alt="PrismaStudio" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159463739-764e709b-9ce9-469b-ada2-dce371a8efad.png" alt="PrismaStudio" /></p>
<h3 id="heading-manually-adding-the-records">Manually adding the records</h3>
<p>Lets manually add some records and save the changes that we made.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159464112-a0575030-4b00-455a-8698-48983f534d39.png" alt="PrismaStudio" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159473084-776a272e-0186-42eb-8905-27e6de0ce1c4.png" alt="DataFilled" /></p>
<p>Finally, lets create a functionality to access that data from within our Next.js app, where we can create new records, update existing ones, and delete old ones.</p>
<h2 id="heading-interacting-with-data-using-nextjs">Interacting with data using Next.js</h2>
<p>You should see some demo datas if you look at the <code>Product</code> page of your application.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159481862-f5f5cb2f-52f4-4b52-80a3-2cb63f41a43d.png" alt="LandingShopButton" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159481958-aeaab5e3-a495-47f8-acce-980701262a5f.png" alt="Product Page" /></p>
<p>Now, open the file <code>pages/products.js</code>, file which represents our app's product page.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/products.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Grid"</span>;

<span class="hljs-keyword">import</span> products <span class="hljs-keyword">from</span> <span class="hljs-string">"products.json"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 p-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">products</span>=<span class="hljs-string">{products}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>As you can see, products data is comming from <code>products.json</code> file.</p>
<pre><code class="lang-json"><span class="hljs-comment">// products.json</span>
[
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"001"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/ballpen_300.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Ball Pen"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">50</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"002"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/actioncamera_300.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Go-pro cam"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">30</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"003"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/alarmclock_300.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Alarm Clock"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">20</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"004"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/bangle_600.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Bangle"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">200</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"005"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/bed_600.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Large Bed"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"out of stock!"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">105</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"006"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/binderclip_600.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Binder clip"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">2</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"007"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/beyblade_600.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"BeyBlade Burst"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"out of stock!"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">15</span>
  },
  {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"008"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"/products/boxinggloves_600.png"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Boxing gloves"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>,
    <span class="hljs-attr">"authenticity"</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">"returnPolicy"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-attr">"status"</span>: <span class="hljs-string">"new"</span>,
    <span class="hljs-attr">"warranty"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-number">45</span>
  }
]
</code></pre>
<p>This data &amp; information is then passed as a prop from the <code>Product</code> component to the <code>Grid</code> component. The <code>Grid</code> component is then in charge of rendering those data as a grid of Card on the screen.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Products.js</span>
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"prop-types"</span>;
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Card"</span>;
<span class="hljs-keyword">import</span> { ExclamationIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/outline"</span>;

<span class="hljs-keyword">const</span> Grid = <span class="hljs-function">(<span class="hljs-params">{ products = [] }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isEmpty = products.length === <span class="hljs-number">0</span>;

  <span class="hljs-keyword">return</span> isEmpty ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-purple-700 bg-amber-100 px-4 rounded-md py-2 max-w-max inline-flex items-center space-x-1"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ExclamationIcon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shrink-0 w-5 h-5 mt-px"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>No data to be displayed.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
  ) : (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"</span>&gt;</span>
      {products.map((product) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span> {<span class="hljs-attr">...product</span>} <span class="hljs-attr">onClickFavorite</span>=<span class="hljs-string">{toggleFavorite}</span> /&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

Grid.propTypes = {
  <span class="hljs-attr">products</span>: PropTypes.array,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Grid;
</code></pre>
<p>Now we want to retrieve data from our database, and we'll do so using Server-Side Rendering (SSR). The ability of an application to convert HTML files on the server into a fully rendered HTML page for the client is known as server-side rendering (SSR). The web browser sends a request for information to the server, which responds immediately by sending the client a fully rendered page.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159494240-00db1ac9-7f1d-4dbe-88ef-0bdd3c196ac5.png" alt="SSR" /></p>
<p>So, in order to use Server Side Rendering(SSR) with <code>Next.js</code>, we must export an asynchronous function <code>getServerSideProps</code> from within the file, which exports the page where we want to render out our data. The data returned by the <code>getServerSideProps</code> function will then be used by <code>Next.js</code> to pre-render our page on each individual request. Let's get started and export this function from our applicartion's <code>Prodcuts</code> page.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/products.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Grid"</span>;

<span class="hljs-keyword">import</span> products <span class="hljs-keyword">from</span> <span class="hljs-string">"products.json"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      <span class="hljs-comment">// props for the Home component</span>
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 p-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">products</span>=<span class="hljs-string">{products}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>To get the data from supabase, import and instantiate the <code>generated Prisma client</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/products.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Grid"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">import</span> products <span class="hljs-keyword">from</span> <span class="hljs-string">"products.json"</span>;

<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      <span class="hljs-comment">// props for the Home component</span>
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 p-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">products</span>=<span class="hljs-string">{products}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, Using the <code>findMany</code> query, we can get all of the records in our Product table:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/products.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> Grid <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Grid"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> prisma.product.findMany();
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      <span class="hljs-attr">products</span>: <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(products)),
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params">{ products = [] }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 p-5"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">products</span>=<span class="hljs-string">{products}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>Simply re-run the application, but if you get an error that looks like the one below, you'll need to regenerate the prisma and then re-run the server.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159522918-6f09bba1-2577-4118-9ed2-b597bcb90794.png" alt="Error" /></p>
<p>As you can see, its fixed now</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159523214-7b6ff048-327d-4e71-b9f3-f5360102b6f9.png" alt="Fixed error" /></p>
<p>Finally, your application should resemble something like this:</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159528273-977d0514-9618-441a-9f7e-3ad461159fa9.png" alt="Application Final Demno" /></p>
<p>Lets give users the functionality to actually create records from the application itself. So, first step is to actually create.</p>
<h2 id="heading-create-a-new-records">Create a new records</h2>
<p>Head over to the <code>pages/</code> folder and make a new file called <code>addProduct.js</code>.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159563363-3253d40c-e2e0-4ed7-99dd-3f90e642791e.png" alt="Folder structure" /></p>
<pre><code class="lang-js"><span class="hljs-comment">// addProducts.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> ProductList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ProductList"</span>;

<span class="hljs-keyword">const</span> addProducts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> createProduct = <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-xl mx-auto flex-col"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-medium text-gray-200 justify-center"</span>&gt;</span>
          Add your Products
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ProductList</span>
            <span class="hljs-attr">buttonText</span>=<span class="hljs-string">"Add Product"</span>
            <span class="hljs-attr">redirectPath</span>=<span class="hljs-string">"/products"</span>
            <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{createProduct}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> addProducts;
</code></pre>
<p>After that head over to the <code>ProductList</code> component and make the following changes to that component.</p>
<pre><code class="lang-js"><span class="hljs-comment">//components/ProductList.js</span>
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"prop-types"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">"yup"</span>;
<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> { Formik, Form } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> Input <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Input"</span>;
<span class="hljs-keyword">import</span> AddProductImage <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/AddProductImage"</span>;

<span class="hljs-keyword">const</span> ProductSchema = Yup.object().shape({
  <span class="hljs-attr">title</span>: Yup.string().trim().required(),
  <span class="hljs-attr">description</span>: Yup.string().trim().required(),
  <span class="hljs-attr">status</span>: Yup.string().trim().required(),
  <span class="hljs-attr">price</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">authenticity</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">returnPolicy</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">warranty</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
});

<span class="hljs-keyword">const</span> ProductList = ({
  initialValues = <span class="hljs-literal">null</span>,
  redirectPath = <span class="hljs-string">""</span>,
  buttonText = <span class="hljs-string">"Submit"</span>,
  onSubmit = <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>,
}) =&gt; {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">const</span> [disabled, setDisabled] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [imageUrl, setImageUrl] = useState(initialValues?.image ?? <span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> upload = <span class="hljs-keyword">async</span> (image) =&gt; {
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Upload image to remote storage</span>
  };

  <span class="hljs-keyword">const</span> handleOnSubmit = <span class="hljs-keyword">async</span> (values = <span class="hljs-literal">null</span>) =&gt; {
    <span class="hljs-keyword">let</span> toastId;
    <span class="hljs-keyword">try</span> {
      setDisabled(<span class="hljs-literal">true</span>);
      toastId = toast.loading(<span class="hljs-string">"Submitting..."</span>);
      <span class="hljs-comment">// Submit data</span>
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> onSubmit === <span class="hljs-string">"function"</span>) {
        <span class="hljs-keyword">await</span> onSubmit({ ...values, <span class="hljs-attr">image</span>: imageUrl });
      }
      toast.success(<span class="hljs-string">"Successfully submitted"</span>, { <span class="hljs-attr">id</span>: toastId });
      <span class="hljs-comment">// Redirect user</span>
      <span class="hljs-keyword">if</span> (redirectPath) {
        router.push(redirectPath);
      }
    } <span class="hljs-keyword">catch</span> (e) {
      toast.error(<span class="hljs-string">"Unable to submit"</span>, { <span class="hljs-attr">id</span>: toastId });
      setDisabled(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">const</span> { image, ...initialFormValues } = initialValues ?? {
    <span class="hljs-attr">image</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">status</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">authenticity</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">returnPolicy</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">warranty</span>: <span class="hljs-number">1</span>,
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
        <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{initialFormValues}</span>
        <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{ProductSchema}</span>
        <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>
        <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleOnSubmit}</span>
      &gt;</span>
        {({ isSubmitting, isValid }) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Title"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Entire your product name..."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"textarea"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Description"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your product description...."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                <span class="hljs-attr">rows</span>=<span class="hljs-string">{3}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"status"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Status(new/out-of-stock/used)"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your product status...."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"price"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Price of the product..."</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"100"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"justify-center"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"authenticity"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"authenticity(%)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"2"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"returnPolicy"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"returnPolicy(? years)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"1"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"warranty"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"warranty(? years)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"1"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled</span> || !<span class="hljs-attr">isValid</span>}
                <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-success text-white py-2 px-6 rounded-md focus:outline-none focus:ring-4 focus:ring-teal-600 focus:ring-opacity-50 hover:bg-teal-500 transition disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-teal-600"</span>
              &gt;</span>
                {isSubmitting ? "Submitting..." : buttonText}
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 max-w-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AddProductImage</span>
          <span class="hljs-attr">initialImage</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">src:</span> <span class="hljs-attr">image</span>, <span class="hljs-attr">alt:</span> <span class="hljs-attr">initialFormValues.title</span> }}
          <span class="hljs-attr">onChangePicture</span>=<span class="hljs-string">{upload}</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

ProductList.propTypes = {
  <span class="hljs-attr">initialValues</span>: PropTypes.shape({
    <span class="hljs-attr">image</span>: PropTypes.string,
    <span class="hljs-attr">title</span>: PropTypes.string,
    <span class="hljs-attr">description</span>: PropTypes.string,
    <span class="hljs-attr">status</span>: PropTypes.string,
    <span class="hljs-attr">price</span>: PropTypes.number,
    <span class="hljs-attr">authenticity</span>: PropTypes.number,
    <span class="hljs-attr">returnPolicy</span>: PropTypes.number,
    <span class="hljs-attr">warranty</span>: PropTypes.number,
  }),
  <span class="hljs-attr">redirectPath</span>: PropTypes.string,
  <span class="hljs-attr">buttonText</span>: PropTypes.string,
  <span class="hljs-attr">onSubmit</span>: PropTypes.func,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductList;
</code></pre>
<p>After that, go to the <code>AddProductImage</code> file inside the component folder and copy the following code.</p>
<pre><code class="lang-js"><span class="hljs-comment">// AddProductImage.js</span>
<span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"prop-types"</span>;
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> toast <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> classNames <span class="hljs-keyword">from</span> <span class="hljs-string">"classnames"</span>;
<span class="hljs-keyword">import</span> { CloudUploadIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/outline"</span>;

<span class="hljs-keyword">const</span> AddProductImage = ({
  label = <span class="hljs-string">"Image"</span>,
  initialImage = <span class="hljs-literal">null</span>,
  objectFit = <span class="hljs-string">"cover"</span>,
  accept = <span class="hljs-string">".png, .jpg, .jpeg, .gif .jiff"</span>,
  sizeLimit = <span class="hljs-number">10</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>,
  onChangePicture = <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>,
}) =&gt; {
  <span class="hljs-keyword">const</span> pictureRef = useRef();
  <span class="hljs-keyword">const</span> [image, setImage] = useState(initialImage ?? <span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [updatingPicture, setUpdatingPicture] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [pictureError, setPictureError] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleOnChangePicture = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> file = e.target.files[<span class="hljs-number">0</span>];
    <span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> FileReader();
    <span class="hljs-keyword">const</span> fileName = file?.name?.split(<span class="hljs-string">"."</span>)?.[<span class="hljs-number">0</span>] ?? <span class="hljs-string">"New file"</span>;

    reader.addEventListener(
      <span class="hljs-string">"load"</span>,
      <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">try</span> {
          setImage({ <span class="hljs-attr">src</span>: reader.result, <span class="hljs-attr">alt</span>: fileName });
          <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> onChangePicture === <span class="hljs-string">"function"</span>) {
            <span class="hljs-keyword">await</span> onChangePicture(reader.result);
          }
        } <span class="hljs-keyword">catch</span> (err) {
          toast.error(<span class="hljs-string">"Unable to update image"</span>);
        } <span class="hljs-keyword">finally</span> {
          setUpdatingPicture(<span class="hljs-literal">false</span>);
        }
      },
      <span class="hljs-literal">false</span>
    );

    <span class="hljs-keyword">if</span> (file) {
      <span class="hljs-keyword">if</span> (file.size &lt;= sizeLimit) {
        setUpdatingPicture(<span class="hljs-literal">true</span>);
        setPictureError(<span class="hljs-string">""</span>);
        reader.readAsDataURL(file);
      } <span class="hljs-keyword">else</span> {
        setPictureError(<span class="hljs-string">"File size is exceeding 10MB."</span>);
      }
    }
  };

  <span class="hljs-keyword">const</span> handleOnClickPicture = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (pictureRef.current) {
      pictureRef.current.click();
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col space-y-2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-200 "</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">disabled</span>=<span class="hljs-string">{updatingPicture}</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleOnClickPicture}</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">{classNames(</span>
          "<span class="hljs-attr">relative</span> <span class="hljs-attr">aspect-video</span> <span class="hljs-attr">overflow-hidden</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">disabled:opacity-50</span> <span class="hljs-attr">disabled:cursor-not-allowed</span> <span class="hljs-attr">transition</span> <span class="hljs-attr">group</span> <span class="hljs-attr">focus:outline-none</span>",
          <span class="hljs-attr">image</span>?<span class="hljs-attr">.src</span>
            ? "<span class="hljs-attr">hover:opacity-50</span> <span class="hljs-attr">disabled:hover:opacity-100</span>"
            <span class="hljs-attr">:</span> "<span class="hljs-attr">border-2</span> <span class="hljs-attr">border-dotted</span> <span class="hljs-attr">hover:border-gray-400</span> <span class="hljs-attr">focus:border-gray-400</span> <span class="hljs-attr">disabled:hover:border-gray-200</span>"
        )}
      &gt;</span>
        {image?.src ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{image.src}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{image?.alt</span> ?? ""}
            <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
            <span class="hljs-attr">objectFit</span>=<span class="hljs-string">{objectFit}</span>
          /&gt;</span>
        ) : null}

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center"</span>&gt;</span>
          {!image?.src ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center space-y-2"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shrink-0 rounded-full p-2 bg-gray-200 group-hover:scale-110 group-focus:scale-110 transition"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">CloudUploadIcon</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-4 h-4 text-gray-500 transition"</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xs font-semibold text-gray-500 transition"</span>&gt;</span>
                {updatingPicture
                  ? "Image Uploading..."
                  : "Upload product Image"}
              <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          ) : null}
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{pictureRef}</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span>
            <span class="hljs-attr">accept</span>=<span class="hljs-string">{accept}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleOnChangePicture}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"hidden"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      {pictureError ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-red-600 text-sm"</span>&gt;</span>{pictureError}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      ) : null}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

AddProductImage.propTypes = {
  <span class="hljs-attr">label</span>: PropTypes.string,
  <span class="hljs-attr">initialImage</span>: PropTypes.shape({
    <span class="hljs-attr">src</span>: PropTypes.string,
    <span class="hljs-attr">alt</span>: PropTypes.string,
  }),
  <span class="hljs-attr">objectFit</span>: PropTypes.string,
  <span class="hljs-attr">accept</span>: PropTypes.string,
  <span class="hljs-attr">sizeLimit</span>: PropTypes.number,
  <span class="hljs-attr">onChangePicture</span>: PropTypes.func,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddProductImage;
</code></pre>
<p>This <code>addProduct</code> component renders the entire page's layout, which consist of a form from where you can add the product details and informations.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159575908-1488990b-6982-446d-901a-27d72aeff82e.png" alt="Demo" /></p>
<h3 id="heading-api-endpoint">API endpoint</h3>
<p>Let's actually create a API endpoint that will actually create a new record on our database via <code>addProduct</code> function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> createProduct = <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>;
</code></pre>
<p>But first, within our <code>Next.js</code> application project, let's create an <code>API</code> endpoint to handle our <code>POST</code> request for creating new records. <code>Next.js</code> provides a file based API routing so any file in the <code>pages/api</code> folder is mapped to <code>/api/*</code> and treated as an API endpoint rather than a page. They're only <code>server-side</code> bundles, so they won't add to the size of your <code>client-side</code> bundle. So, create a file name called <code>products.js</code> inside the <code>pages/api</code> folder and inside it create a request handler fucntion like shown below.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{}
</code></pre>
<h4 id="heading-handling-post-request-for-products">Handling <code>POST</code> request for <code>products</code></h4>
<p>Before we go any further, use <code>req.method</code> to check the <code>HTTP</code> method of the request inside that <code>request handler</code> function. After that, return a 405 status code to the client becasue we are not handlling any kind of HTTP method.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/api/products.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
    <span class="hljs-comment">// TODO</span>
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method <span class="hljs-subst">${req.method}</span> is not supported.`</span> });
  }
}
</code></pre>
<h4 id="heading-adding-new-records-with-prisma-client">Adding new records with Prisma Client</h4>
<p>Now, lets use Prisma Client to create a new <code>Product</code> record in the database using the data from the current HTTP request.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/api/products.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
    <span class="hljs-keyword">const</span> {
      image,
      title,
      description,
      status,
      price,
      authenticity,
      returnPolicy,
      warranty,
    } = req.body;
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method <span class="hljs-subst">${req.method}</span> is not supported.`</span> });
  }
}
</code></pre>
<p>After that, lets actually initialize <code>Prisma</code> and call the <code>create</code> function that prisma provides.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;

<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
    <span class="hljs-keyword">const</span> {
      image,
      title,
      description,
      status,
      price,
      authenticity,
      returnPolicy,
      warranty,
    } = req.body;

    <span class="hljs-keyword">const</span> home = <span class="hljs-keyword">await</span> prisma.product.create({
      <span class="hljs-attr">data</span>: {
        image,
        title,
        description,
        status,
        price,
        authenticity,
        returnPolicy,
        warranty,
      },
    });
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method <span class="hljs-subst">${req.method}</span> is not supported.`</span> });
  }
}
</code></pre>
<p>Finally lets add some try catch block to Handle the error.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/api/products.js</span>
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> {
        image,
        title,
        description,
        status,
        price,
        authenticity,
        returnPolicy,
        warranty,
      } = req.body;

      <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> prisma.product.create({
        <span class="hljs-attr">data</span>: {
          image,
          title,
          description,
          status,
          price,
          authenticity,
          returnPolicy,
          warranty,
        },
      });
      res.status(<span class="hljs-number">200</span>).json(product);
    } <span class="hljs-keyword">catch</span> (e) {
      res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Something went wrong"</span> });
    }
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method <span class="hljs-subst">${req.method}</span> is not supported.`</span> });
  }
}
</code></pre>
<p>Now that we've created our <code>API</code>, let's call the API endpoint. To do so, open the <code>addProduct.js</code> file in the <code>pages</code> folder and make the following changes to the code, but first, we'll need to install the <code>axios</code> package, so do that first.</p>
<pre><code class="lang-bash">npm i axios
</code></pre>
<p>OR</p>
<pre><code class="lang-bash">yarn add axios
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/159638586-5cf82100-c3dc-4dbc-a4a8-7188408aba4c.png" alt="Axios" /></p>
<pre><code class="lang-js"><span class="hljs-comment">//pages/addProducts.js</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> ProductList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ProductList"</span>;

<span class="hljs-keyword">const</span> addProducts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> createProduct = <span class="hljs-function">() =&gt;</span> <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> axios.post(<span class="hljs-string">"/api/products"</span>, data);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-xl mx-auto flex-col"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-medium text-gray-200 justify-center"</span>&gt;</span>
          Add your Products
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ProductList</span>
            <span class="hljs-attr">buttonText</span>=<span class="hljs-string">"Add Product"</span>
            <span class="hljs-attr">redirectPath</span>=<span class="hljs-string">"/products"</span>
            <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{createProduct}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> addProducts;
</code></pre>
<p>Now lets re-run the server again.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159643456-282dfb5e-2963-44f7-920e-1db0cc4cfa4e.png" alt="image" /></p>
<p>After that head over to your browser and go to the <code>http://localhost:3000/addProducts</code> route and fill out all the product information and <code>Submit</code> it.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159903073-4fd2e7ed-7317-4011-9700-9305fd8e875e.png" alt="Demo" />
<img src="https://user-images.githubusercontent.com/37651620/159903115-4347de95-d5e1-4747-8f45-acae6b99d969.png" alt="Demo" />
<img src="https://user-images.githubusercontent.com/37651620/159903149-710afad5-015b-4dc3-b3e6-8281a300820f.png" alt="Demo" /></p>
<p>It will automatically redirect you to the <code>/products</code> page and you should be able to see the product that you just added.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159903167-ae9c4c76-aab3-4fff-880b-fb1a1e6a1d70.png" alt="Demo" /></p>
<h2 id="heading-pre-rendering-the-pages">Pre-rendering the pages</h2>
<p>We've used the <code>getServerSideProps</code> function to pre-render the <code>product</code> of our app using <code>Server-Side Rendering(SSR)</code>. Next.js, on the other hand, comes with a <code>built-in</code> pre-rendering method called <code>Static Generation (SSG)</code>.</p>
<p>When a page uses Static Generation, the HTML for that page is generated during the build process. That means that when you run next build in production, the page HTML is generated. Each request will then be served with the same HTML. A <code>CDN</code> can cache it. You can statically generate pages with or without data using <code>Next.js</code>.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159921224-aadedf3e-aaf1-4457-a5f9-486289bd28c6.png" alt="SSG" /></p>
<p>We can use different <code>pre-rendering</code> techniques on our applications when we use a framework like <code>Next.js</code>. For something more simple and non-dynamic, we can use <code>static site generation(SSG)</code>. For dynamic content and more complex pages, we can use <code>server-side rendering(SSR)</code> .</p>
<h3 id="heading-dynamic-routing-with-ssg">Dynamic Routing with SSG</h3>
<p>We can still statically generate pages with SSG after fetching some external data during the build process, even if SSG generates HTML at build time. <a target="_blank" href="https://nextjs.org/docs/basic-features/pages">learn more about static generation and dynamic routing</a>.</p>
<p>Let's get data at build time by exporting an <code>async</code> function called <code>getStaticProps</code> from the pages we want to statically generate.</p>
<h3 id="heading-for-example">For Example,</h3>
<pre><code class="lang-js"><span class="hljs-comment">// posts will be populated at build time by getStaticProps()</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Blog</span>(<span class="hljs-params">{ posts }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {posts.map((post) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
  );
}
<span class="hljs-comment">// This function gets called at build time on server-side.</span>
<span class="hljs-comment">// It won't be called on client-side, so you can even do</span>
<span class="hljs-comment">// direct database queries.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Call an external API endpoint to get posts.</span>
  <span class="hljs-comment">// You can use any data fetching library</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://.../posts"</span>);
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> res.json();
  <span class="hljs-comment">// By returning { props: { posts } }, the Blog component</span>
  <span class="hljs-comment">// will receive `posts` as a prop at build time</span>
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      posts,
    },
  };
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Blog;
</code></pre>
<p>Let's put Static Generation(SSG) to work in our application. The pages that render each individual <code>Product</code> listing are the ones that we'll statically generate at the build time. However, because <code>product</code> listings are generated through the users, we could end up with massive amount of pages. As a result, we won't be able to define those routes using predefined paths. Otherwise, we'll end up with a slew of useless files cluttering up our project.</p>
<p>We can easily create dynamic routes in <code>Next.js</code>. We just need to add brackets to a page's filename, <code>[id].js</code>, to create a dynamic route. However, in our project, we will place that in the <code>Products</code> folder. As a result, any route's <code>ids</code> will be matched with their specific id value, and the id value will be available inside the React component that renders the associated page.</p>
<p>Now, go to the pages folder and make a new folder called <code>products</code>, then make a new file called <code>[id].js</code> inside it.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159926080-e55b1760-02eb-41a6-a8ac-84a4c2c8b49b.png" alt="products" /></p>
<p>And finally paste the following code inside that file.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/products/[id].jsx</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;

<span class="hljs-keyword">const</span> ListedProducts = <span class="hljs-function">(<span class="hljs-params">product = <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-lg mx-auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 relative aspect-video bg-gray-400 rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          {product?.image ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
              <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
              <span class="hljs-attr">objectFit</span>=<span class="hljs-string">"cover"</span>
            /&gt;</span>
          ) : null}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row sm:justify-between sm:space-x-4 space-y-4 pt-10"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold truncate"</span>&gt;</span>
              {product?.title ?? ""}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center space-x-1 text-info"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.status ?? 0} product<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.authenticity ?? 0}% Authentic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.returnPolicy ?? 0} year return policy<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.warranty ?? 0} year warranty<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 text-lg"</span>&gt;</span>{product?.description ?? ""}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListedProducts;
</code></pre>
<p>Now, let's actually provide the lists of paths of the pages that we want to statically generate, and let's actually fetch some data and match it with the numbers of paths. To do so, we must provide the paths to Next.js that we want to pre-render at build time.This function should return all the paths of the pages to pre-render at build time, along with the corresponding <code>id</code> value in the returned object's params property. So for that, we'll be using Prisma to retrieve the IDs for all of the <code>products</code> residing on our database.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/products/[id].jsx</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
<span class="hljs-comment">// Instantiate Prisma Client</span>
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">const</span> ListedProducts = <span class="hljs-function">(<span class="hljs-params">product = <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-lg mx-auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 relative aspect-video bg-gray-400 rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          {product?.image ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
              <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
              <span class="hljs-attr">objectFit</span>=<span class="hljs-string">"cover"</span>
            /&gt;</span>
          ) : null}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row sm:justify-between sm:space-x-4 space-y-4 pt-10"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold truncate"</span>&gt;</span>
              {product?.title ?? ""}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center space-x-1 text-info"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.status ?? 0} product<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.authenticity ?? 0}% Authentic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.returnPolicy ?? 0} year return policy<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.warranty ?? 0} year warranty<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 text-lg"</span>&gt;</span>{product?.description ?? ""}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> prisma.product.findMany({
    <span class="hljs-attr">select</span>: { <span class="hljs-attr">id</span>: <span class="hljs-literal">true</span> },
  });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> ({
      <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: product.id },
    })),
    <span class="hljs-attr">fallback</span>: <span class="hljs-literal">false</span>,
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListedProducts;
</code></pre>
<p>The <code>getStaticProps</code> function must now be implemented. So, let's get started. As you can see, the first thing we do is use the Prisma findUnique function with the id retrieved from the query params object to get the data of the requested route. Then, if the corresponding home is found in the database, we return it to the <code>ListedProducts</code> React component as a prop. If the requested <code>products</code> cannot be found, we return an object to tell Next.js to redirect the user to our app's '<code>products'</code> page.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/products/[id].jsx</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
<span class="hljs-comment">// Instantiate Prisma Client</span>
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">const</span> ListedProducts = <span class="hljs-function">(<span class="hljs-params">product = <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-lg mx-auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 relative aspect-video bg-gray-400 rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          {product?.image ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
              <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
              <span class="hljs-attr">objectFit</span>=<span class="hljs-string">"cover"</span>
            /&gt;</span>
          ) : null}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row sm:justify-between sm:space-x-4 space-y-4 pt-10"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold truncate"</span>&gt;</span>
              {product?.title ?? ""}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center space-x-1 text-info"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.status ?? 0} product<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.authenticity ?? 0}% Authentic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.returnPolicy ?? 0} year return policy<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.warranty ?? 0} year warranty<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 text-lg"</span>&gt;</span>{product?.description ?? ""}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> prisma.product.findMany({
    <span class="hljs-attr">select</span>: { <span class="hljs-attr">id</span>: <span class="hljs-literal">true</span> },
  });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> ({
      <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: product.id },
    })),
    <span class="hljs-attr">fallback</span>: <span class="hljs-literal">false</span>,
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> prisma.product.findUnique({
    <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: params.id },
  });

  <span class="hljs-keyword">if</span> (product) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">props</span>: <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(product)),
    };
  }

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">redirect</span>: {
      <span class="hljs-attr">destination</span>: <span class="hljs-string">"/products"</span>,
      <span class="hljs-attr">permanent</span>: <span class="hljs-literal">false</span>,
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListedProducts;
</code></pre>
<p>Now re-run the server and head back to the browser and open the application.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160119909-00de7d20-ea1c-448e-b674-b9a752f2308b.png" alt="Demo" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160119847-283970a1-f083-4427-ac80-535418353cc7.gif" alt="Demo" /></p>
<h2 id="heading-implementing-incremental-static-generationisr">Implementing Incremental Static Generation(ISR)</h2>
<p>If you try to access a page for a new <code>product</code> listing in production, you'll get a <code>404 error page</code> instead. To see this in action, build your app and run it as you would in production, because <code>getStaticProps</code> runs on every request in development. So, we have different behavior in development that differs from what we would see in <code>production</code>. To serve a production build of your application, simply fire up the following command, but make sure to stop the server first.</p>
<pre><code class="lang-bash">yarn build
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/160135075-4666a8d8-5f74-471d-9b60-aea22b889896.png" alt="yarn build" /></p>
<pre><code class="lang-bash">yarn start
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/160135296-cfe7f272-b810-4b70-a56b-909dea7d05f5.png" alt="yarn start" /></p>
<p>The main reason for the <code>404 page</code> is that we used Static Generation to define the routes <code>/products/[id].js</code>, and we only generated pages for the products that were in our database at the time. In other words, after this build process, none of the products our users create will generate a new page. That is why we have a <code>404 page</code> instead, because the page simply does not exist at all.To fix this, we'll need to define a fallback that will allow us to continue building pages lazily at runtime.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/products/[id].js</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
<span class="hljs-comment">// Instantiate Prisma Client</span>
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">const</span> ListedProducts = <span class="hljs-function">(<span class="hljs-params">product = <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-lg mx-auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 relative aspect-video bg-gray-400 rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          {product?.image ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
              <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
              <span class="hljs-attr">objectFit</span>=<span class="hljs-string">"cover"</span>
            /&gt;</span>
          ) : null}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row sm:justify-between sm:space-x-4 space-y-4 pt-10"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold truncate"</span>&gt;</span>
              {product?.title ?? ""}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center space-x-1 text-info"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.status ?? 0} product<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.authenticity ?? 0}% Authentic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.returnPolicy ?? 0} year return policy<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.warranty ?? 0} year warranty<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 text-lg"</span>&gt;</span>{product?.description ?? ""}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> prisma.product.findMany({
    <span class="hljs-attr">select</span>: { <span class="hljs-attr">id</span>: <span class="hljs-literal">true</span> },
  });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> ({
      <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: product.id },
    })),
    <span class="hljs-comment">// ----- SET to TRUE ------</span>
    <span class="hljs-attr">fallback</span>: <span class="hljs-literal">true</span>,
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> prisma.product.findUnique({
    <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: params.id },
  });

  <span class="hljs-keyword">if</span> (product) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">props</span>: <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(product)),
    };
  }

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">redirect</span>: {
      <span class="hljs-attr">destination</span>: <span class="hljs-string">"/products"</span>,
      <span class="hljs-attr">permanent</span>: <span class="hljs-literal">false</span>,
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListedProducts;
</code></pre>
<p>Now that we've set the <code>fallback</code> to <code>true</code>, the <code>404</code> page will no longer be displayed.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160141955-14e4651c-bfc4-4dc2-8418-53d5b1639bce.gif" alt="Fallback" /></p>
<p>It's also possible to detect whether the fallback version of the page is being rendered with the <code>Next.js router</code> and, if so, conditionally render something else, such as a loading spinner, while we wait for the props to get loaded.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> router = useRouter();

<span class="hljs-keyword">if</span> (router.isFallback) {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
      <span class="hljs-attr">role</span>=<span class="hljs-string">"status"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"mr-2 w-14 h-14 text-gray-200 animate-spin dark:text-gray-600 fill-success"</span>
      <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 100 101"</span>
      <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
      <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
        <span class="hljs-attr">d</span>=<span class="hljs-string">"M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"</span>
        <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
        <span class="hljs-attr">d</span>=<span class="hljs-string">"M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"</span>
        <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentFill"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span></span>
  );
}
</code></pre>
<p>Finally your <code>[id].js</code> code should look something like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/products/[id].js</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Layout"</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@prisma/client"</span>;
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">const</span> ListedProducts = <span class="hljs-function">(<span class="hljs-params">product = <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">if</span> (router.isFallback) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
        <span class="hljs-attr">role</span>=<span class="hljs-string">"status"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"mr-2 w-14 h-14 text-gray-200 animate-spin dark:text-gray-600 fill-success"</span>
        <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 100 101"</span>
        <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
        <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
          <span class="hljs-attr">d</span>=<span class="hljs-string">"M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"</span>
          <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
          <span class="hljs-attr">d</span>=<span class="hljs-string">"M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"</span>
          <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentFill"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span></span>
    );
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-screen-lg mx-auto"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 relative aspect-video bg-gray-400 rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          {product?.image ? (
            <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.title}</span>
              <span class="hljs-attr">layout</span>=<span class="hljs-string">"fill"</span>
              <span class="hljs-attr">objectFit</span>=<span class="hljs-string">"cover"</span>
            /&gt;</span>
          ) : null}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col sm:flex-row sm:justify-between sm:space-x-4 space-y-4 pt-10"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-semibold truncate"</span>&gt;</span>
              {product?.title ?? ""}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center space-x-1 text-info"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.status ?? 0} product<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.authenticity ?? 0}% Authentic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.returnPolicy ?? 0} year return policy<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> - <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ( <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{product?.warranty ?? 0} year warranty<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span> ) <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 text-lg"</span>&gt;</span>{product?.description ?? ""}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> prisma.product.findMany({
    <span class="hljs-attr">select</span>: { <span class="hljs-attr">id</span>: <span class="hljs-literal">true</span> },
  });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">paths</span>: products.map(<span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> ({
      <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: product.id },
    })),
    <span class="hljs-attr">fallback</span>: <span class="hljs-literal">false</span>,
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> prisma.product.findUnique({
    <span class="hljs-attr">where</span>: { <span class="hljs-attr">id</span>: params.id },
  });

  <span class="hljs-keyword">if</span> (product) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">props</span>: <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(product)),
    };
  }

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">redirect</span>: {
      <span class="hljs-attr">destination</span>: <span class="hljs-string">"/products"</span>,
      <span class="hljs-attr">permanent</span>: <span class="hljs-literal">false</span>,
    },
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListedProducts;
</code></pre>
<h2 id="heading-uploading-image-in-supabase">Uploading image in Supabase</h2>
<p>We've created product records up to this point, but without any images because we haven't yet implemented aby media storage. We'll use Supabase Storage, a fantastic service from Supabase, to store and use media files in our project.</p>
<h3 id="heading-creating-a-bucket-in-supabase">Creating a bucket in supabase</h3>
<p>Buckets are distinct containers for files and folders. It is like a <code>super folders</code>. Generally you would create distinct buckets for different Security and Access Rules. For example, you might keep all public files in a <code>public</code> bucket, and other files that require logged-in access in a <code>restricted</code> bucket.</p>
<p>To create a bucket in Supabase, first navigate to the <code>storage</code> section of the dashboard.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160153539-6c318c5c-0dee-4da2-9916-8f8801961afa.gif" alt="Storage" /></p>
<p>After that, select <code>Create Bucket</code> button.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160153764-f0f71f25-a3e0-44cf-90ba-f966397a18be.png" alt="Storage" /></p>
<p>Next, give the bucket a name; for now, we'll call it <code>supabase-ecommerce</code>, and remember to make it public and click on that <code>Create Button</code> button.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160154077-c0fe180d-2571-4497-8c58-2ae23e89e660.png" alt="Storage" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160154148-e235236a-732e-4008-bb2a-6aa8b9ba592f.png" alt="Storage" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160154311-35f95ab3-ce34-43af-a0f4-dc8541c4de93.png" alt="Storage" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160154342-74a45f3b-eb85-487d-8b58-5a997477aa17.png" alt="Storage" /></p>
<h3 id="heading-manually-uploading-image-on-database">Manually uploading image on database</h3>
<ul>
<li><strong>Step 1</strong>: Head over to the supabase <code>Storage</code> and upload the <code>products</code> images.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160235447-6b9deb1c-0bf6-4a4c-97dc-2732dd220cf4.png" alt="Boxing" />
<img src="https://user-images.githubusercontent.com/37651620/160235455-c39b17f7-8d61-4ddb-ac19-2977afe0cbc2.png" alt="Boxing" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160235495-a605f3b4-2505-4284-bfba-14f9c63f533c.png" alt="Action Camera" />
<img src="https://user-images.githubusercontent.com/37651620/160235505-34065298-562a-4d40-9aae-d7543087909d.png" alt="Action Camera" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160235537-ebc2cb10-9d1a-4311-b208-b340d0627d1c.png" alt="Jwellery" />
<img src="https://user-images.githubusercontent.com/37651620/160235568-7ae8f3cc-6d6a-48a7-b58d-23be839eec87.png" alt="Jwellery" /></p>
<ul>
<li><strong>Step 2</strong>: Select the product image and copy the <code>image url</code></li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160235649-554c8f10-64d3-4ad1-a50d-f3e0faa238fb.png" alt="Boxing" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160235666-52bdedb1-5740-4e1b-a448-9c41c3abd9a7.png" alt="Camera" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160235704-d22b5981-5c7a-4615-b630-19322c36d803.png" alt="Jwellery" /></p>
<ul>
<li><strong>Step 3</strong>: Open up the <code>Prisma Studio</code> by typing <code>npx prisma studio</code> inside the command line terminal.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160236083-fd80ccb4-f7ac-4b4a-9576-ad4f754a9917.png" alt="Prisma Studio" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160236136-f6b62776-16c9-4cbc-b9d6-f858ea82157a.png" alt="Prisma" /></p>
<ul>
<li><strong>Step 3</strong>: Now, paste all of the image urls you copied in 'Step 2' inside the image row.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160236233-9ecfde2d-f335-4cb1-a460-d8c2ae3ea79c.png" alt="Image URL" /></p>
<p>Go back to the application and refresh the page now that you've added all of the <code>image urls</code>. You may encounter the error shown below.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160236310-551486ec-1355-4025-8a0f-af47e51b5ddb.png" alt="Image URL" /></p>
<p>Copy the hostname of your file URL and paste it into the <code>images.domains</code> config in the <code>next.config.js</code> file to fix the error.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">reactStrictMode</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">images</span>: {
    <span class="hljs-attr">domains</span>: [<span class="hljs-string">"ezkjatblqzjynrebjkpq.supabase.co"</span>],
  },
};
</code></pre>
<p>After that, restart the server, and you should see images.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160236559-21b8be68-1042-476f-bc9a-8c0aec3b1930.png" alt="Demo" />
<img src="https://user-images.githubusercontent.com/37651620/160236563-161dcd5a-f664-4868-ba20-9cbca4652f43.png" alt="Demo" />
<img src="https://user-images.githubusercontent.com/37651620/160236579-6f80c2de-accd-4d30-a35b-19a990ca5e48.png" alt="Demo" /></p>
<h3 id="heading-security-rules">Security Rules</h3>
<p>We must define some security rules to be able to deal with our image files inside our bucket using the <code>Supabase API</code>. So, add the security rules from our <code>Supabase dashboard</code>.</p>
<ul>
<li><strong>Step 1</strong>: Head over to the <code>Storage</code> section and go to the <code>Policies</code> section.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238474-ad39e70f-feff-4bfa-a559-b57cc00a0ac4.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 2</strong>: Create a <code>New Policy</code>.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238482-416094e3-5ecf-441f-a8f1-619425257c98.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 3</strong>: Select <code>Get started quickly</code>.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238492-b814238e-1723-40ca-bcfc-5b97979974d0.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 4</strong>: Use <code>Allow access to JPG images in a public folder to anonymous users</code> this template.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238518-fc9066f6-1031-4f95-90bf-74eda3b7b767.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 5</strong>: Give the <code>Policy Name</code> select all the <code>Operation</code> and give <code>bucket_id</code> and Hit <code>Review</code>.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238559-7b2ffdd1-948d-46f9-903a-1e84297d875d.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 6</strong>: <code>Review</code> the policy and <code>save</code> it.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238568-fd77e15b-4265-499e-a89c-4daaf33a8f07.png" alt="Security Rules" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160238578-e542545d-03e9-4072-8466-f3a2eb56c41d.png" alt="Security Rules" /></p>
<ul>
<li><strong>Step 8</strong>: Finally you've successfully created a <code>Storage Policy</code>.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/160238595-7be56c15-4a45-4af5-9e02-1bfe13da601a.png" alt="Security Rules" /></p>
<h2 id="heading-upload-a-file-from-application">Upload a file from application</h2>
<p>Let's keep going and add the ability for our application to upload and store our products images. Let's begin by adding a new <code>API endpoint</code> to your project's <code>pages/api/productsImage.js</code> directory.</p>
<pre><code class="lang-js"><span class="hljs-comment">// pages/api/productsImage.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method :<span class="hljs-subst">${req.method}</span>: not supported.`</span> });
  }
}
</code></pre>
<p>Now, let's use Supabase JS Client for uploading the image to our Supabase Storage Bucket.To do so, you need to install <code>@supabase/supabase-js</code> client library.</p>
<pre><code class="lang-shell">npm i @supabase/supabase-js
</code></pre>
<p><img src="https://user-images.githubusercontent.com/37651620/160239578-b753f67d-d04f-4cca-9c98-ec498077bff8.png" alt="Supbase client" /></p>
<p>Then, inside your <code>pages/api/productsImage.js file</code>, import it and create a new Supabase Client.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/api/productsImage.js</span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;

<span class="hljs-keyword">const</span> supabase = createClient(
  process.env.SUPABASE_API_URL,
  process.env.SUPABASE_API_KEY
);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method :<span class="hljs-subst">${req.method}</span>: not supported.`</span> });
  }
}
</code></pre>
<p>After that, go to the Supabase dashboard and click on <code>Setting &gt; API</code>.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160244953-5476732c-8dd2-44ec-a8ef-545e0da80202.png" alt="API key" /></p>
<p>and add all those API keys to your <code>env</code> file.</p>
<pre><code class="lang-js">SUPABASE_API_KEY =
  <span class="hljs-string">"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV6a2phdGJscXpqeW5yZWJ-"</span>;
SUPABASE_API_URL = <span class="hljs-string">"https://ezkjatblqzjynrebjkpq.supabase.co"</span>;
SUPABASE_STORAGE_BUCKET = <span class="hljs-string">"supabase-ecommerce"</span>;
</code></pre>
<p>Now you need to add three packages to your application. The first one is <code>base64-arraybuffer</code> which encodes and decodes base64 to and from ArrayBuffers and another package called <code>nanoid</code> which is a very tiny, secure, URL-friendly, unique string ID generator for <code>JavaScript</code>.</p>
<pre><code>yarn <span class="hljs-keyword">add</span> nanoid base64-arraybuffer
</code></pre><p><img src="https://user-images.githubusercontent.com/37651620/160245715-13f55bc1-415c-4c25-99d2-c239f86646bf.png" alt="Supabase" /></p>
<p>Return to our API endpoint and upload a file to our bucket using the Supabase Client. Obtain the image data from the request's body and verify that it is not empty, then inspect the image data for <code>Base64 encoding</code>. After that, save the file to your Supbase storage bucket. With the <code>SUPABASE_STORAGE_BUCKET</code> env, you must provide the storage bucket name, the file path, and the decoded Base64 data, as well as the <code>contentType</code>. Once the image has been successfully uploaded, we can generate its public URL and return it to the client who initiated the HTTP request and then do some <code>Error handling</code> .So finally, your <code>API endpoint</code> for <code>productsImage</code> should look like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/api/productsImage.js</span>
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/supabase"</span>;
<span class="hljs-keyword">import</span> { nanoid } <span class="hljs-keyword">from</span> <span class="hljs-string">"nanoid"</span>;
<span class="hljs-keyword">import</span> { decode } <span class="hljs-keyword">from</span> <span class="hljs-string">"base64-arraybuffer"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (req.method === <span class="hljs-string">"POST"</span>) {
    <span class="hljs-keyword">let</span> { image } = req.body;

    <span class="hljs-keyword">if</span> (!image) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"There is no image"</span> });
    }
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> imageType = image.match(<span class="hljs-regexp">/data:(.*);base64/</span>)?.[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">const</span> base64FileData = image.split(<span class="hljs-string">"base64,"</span>)?.[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">if</span> (!imageType || !base64FileData) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Image data not valid"</span> });
      }
      <span class="hljs-keyword">const</span> fileName = nanoid();
      <span class="hljs-keyword">const</span> ext = imageType.split(<span class="hljs-string">"/"</span>)[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">const</span> path = <span class="hljs-string">`<span class="hljs-subst">${fileName}</span>.<span class="hljs-subst">${ext}</span>`</span>;
      <span class="hljs-keyword">const</span> { data, <span class="hljs-attr">error</span>: uploadError } = <span class="hljs-keyword">await</span> supabase.storage
        .from(process.env.SUPABASE_STORAGE_BUCKET)
        .upload(path, decode(base64FileData), {
          imageType,
          <span class="hljs-attr">upsert</span>: <span class="hljs-literal">true</span>,
        });
      <span class="hljs-keyword">if</span> (uploadError) {
        <span class="hljs-built_in">console</span>.log(uploadError);
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Image upload Failed!!"</span>);
      }
      <span class="hljs-keyword">const</span> url = <span class="hljs-string">`<span class="hljs-subst">${process.env.SUPABASE_API_URL.replace(
        <span class="hljs-string">".co"</span>
      )}</span>/storage/v1/object/public/<span class="hljs-subst">${data.Key}</span>`</span>;

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({ url });
    } <span class="hljs-keyword">catch</span> (e) {
      res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Something went horribly wrong"</span> });
    }
  } <span class="hljs-keyword">else</span> {
    res.setHeader(<span class="hljs-string">"Allow"</span>, [<span class="hljs-string">"POST"</span>]);
    res
      .status(<span class="hljs-number">405</span>)
      .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">`HTTP method :<span class="hljs-subst">${req.method}</span>: is not supported.`</span> });
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">api</span>: {
    <span class="hljs-attr">bodyParser</span>: {
      <span class="hljs-attr">sizeLimit</span>: <span class="hljs-string">"15mb"</span>,
    },
  },
};
</code></pre>
<p>After you have added the API endpoint make the following chnages to the <code>ProductList</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/router"</span>;
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">"prop-types"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">"yup"</span>;
<span class="hljs-keyword">import</span> { toast } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> { Formik, Form } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>;
<span class="hljs-keyword">import</span> Input <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Input"</span>;
<span class="hljs-keyword">import</span> AddProductImage <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/AddProductImage"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> ProductSchema = Yup.object().shape({
  <span class="hljs-attr">title</span>: Yup.string().trim().required(),
  <span class="hljs-attr">description</span>: Yup.string().trim().required(),
  <span class="hljs-attr">status</span>: Yup.string().trim().required(),
  <span class="hljs-attr">price</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">authenticity</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">returnPolicy</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
  <span class="hljs-attr">warranty</span>: Yup.number().positive().integer().min(<span class="hljs-number">1</span>).required(),
});

<span class="hljs-keyword">const</span> ProductList = ({
  initialValues = <span class="hljs-literal">null</span>,
  redirectPath = <span class="hljs-string">""</span>,
  buttonText = <span class="hljs-string">"Submit"</span>,
  onSubmit = <span class="hljs-function">() =&gt;</span> <span class="hljs-literal">null</span>,
}) =&gt; {
  <span class="hljs-keyword">const</span> router = useRouter();

  <span class="hljs-keyword">const</span> [disabled, setDisabled] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [imageUrl, setImageUrl] = useState(initialValues?.image ?? <span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> upload = <span class="hljs-keyword">async</span> (image) =&gt; {
    <span class="hljs-keyword">if</span> (!image) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">let</span> toastId;
    <span class="hljs-keyword">try</span> {
      setDisabled(<span class="hljs-literal">true</span>);
      toastId = toast.loading(<span class="hljs-string">"Uploading..."</span>);
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">"/api/productsImage"</span>, { image });
      setImageUrl(data?.url);
      toast.success(<span class="hljs-string">"Successfully uploaded Image"</span>, { <span class="hljs-attr">id</span>: toastId });
    } <span class="hljs-keyword">catch</span> (e) {
      toast.error(<span class="hljs-string">"Unable to upload Image"</span>, { <span class="hljs-attr">id</span>: toastId });
      setImageUrl(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">finally</span> {
      setDisabled(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">const</span> handleOnSubmit = <span class="hljs-keyword">async</span> (values = <span class="hljs-literal">null</span>) =&gt; {
    <span class="hljs-keyword">let</span> toastId;
    <span class="hljs-keyword">try</span> {
      setDisabled(<span class="hljs-literal">true</span>);
      toastId = toast.loading(<span class="hljs-string">"Submitting..."</span>);
      <span class="hljs-comment">// Submit data</span>
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> onSubmit === <span class="hljs-string">"function"</span>) {
        <span class="hljs-keyword">await</span> onSubmit({ ...values, <span class="hljs-attr">image</span>: imageUrl });
      }
      toast.success(<span class="hljs-string">"Successfully submitted"</span>, { <span class="hljs-attr">id</span>: toastId });
      <span class="hljs-comment">// Redirect user</span>
      <span class="hljs-keyword">if</span> (redirectPath) {
        router.push(redirectPath);
      }
    } <span class="hljs-keyword">catch</span> (e) {
      toast.error(<span class="hljs-string">"Unable to submit"</span>, { <span class="hljs-attr">id</span>: toastId });
      setDisabled(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">const</span> { image, ...initialFormValues } = initialValues ?? {
    <span class="hljs-attr">image</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">status</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">authenticity</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">returnPolicy</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">warranty</span>: <span class="hljs-number">1</span>,
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
        <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{initialFormValues}</span>
        <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{ProductSchema}</span>
        <span class="hljs-attr">validateOnBlur</span>=<span class="hljs-string">{false}</span>
        <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleOnSubmit}</span>
      &gt;</span>
        {({ isSubmitting, isValid }) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Title"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Entire your product name..."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"textarea"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Description"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your product description...."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                <span class="hljs-attr">rows</span>=<span class="hljs-string">{3}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"status"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Status(new/out-of-stock/used)"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your product status...."</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"price"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                <span class="hljs-attr">label</span>=<span class="hljs-string">"Price of the product..."</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"100"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
              /&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"justify-center"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"authenticity"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"authenticity(%)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"2"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"returnPolicy"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"returnPolicy(? years)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"1"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
                  <span class="hljs-attr">name</span>=<span class="hljs-string">"warranty"</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
                  <span class="hljs-attr">min</span>=<span class="hljs-string">"0"</span>
                  <span class="hljs-attr">label</span>=<span class="hljs-string">"warranty(? years)"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"1"</span>
                  <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                <span class="hljs-attr">disabled</span>=<span class="hljs-string">{disabled</span> || !<span class="hljs-attr">isValid</span>}
                <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-success text-white py-2 px-6 rounded-md focus:outline-none focus:ring-4 focus:ring-teal-600 focus:ring-opacity-50 hover:bg-teal-500 transition disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-teal-600"</span>
              &gt;</span>
                {isSubmitting ? "Submitting..." : buttonText}
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 max-w-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AddProductImage</span>
          <span class="hljs-attr">initialImage</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">src:</span> <span class="hljs-attr">image</span>, <span class="hljs-attr">alt:</span> <span class="hljs-attr">initialFormValues.title</span> }}
          <span class="hljs-attr">onChangePicture</span>=<span class="hljs-string">{upload}</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

ProductList.propTypes = {
  <span class="hljs-attr">initialValues</span>: PropTypes.shape({
    <span class="hljs-attr">image</span>: PropTypes.string,
    <span class="hljs-attr">title</span>: PropTypes.string,
    <span class="hljs-attr">description</span>: PropTypes.string,
    <span class="hljs-attr">status</span>: PropTypes.string,
    <span class="hljs-attr">price</span>: PropTypes.number,
    <span class="hljs-attr">authenticity</span>: PropTypes.number,
    <span class="hljs-attr">returnPolicy</span>: PropTypes.number,
    <span class="hljs-attr">warranty</span>: PropTypes.number,
  }),
  <span class="hljs-attr">redirectPath</span>: PropTypes.string,
  <span class="hljs-attr">buttonText</span>: PropTypes.string,
  <span class="hljs-attr">onSubmit</span>: PropTypes.func,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductList;
</code></pre>
<p>Now lets actually test our final application</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160247868-452701cd-85d6-4f16-b60f-7a5e14abc49e.png" alt="Demo" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/160247968-01060b50-eed4-4308-8a1f-dc85998b4319.png" alt="Demo" /></p>
<hr />
<h3 id="heading-chatwoot-configuration">Chatwoot Configuration</h3>
<h4 id="heading-chatwoot-configuration-on-heroku">Chatwoot configuration on Heroku</h4>
<p>Let's get started by creating a chatwoot instance on Heroku.</p>
<ul>
<li><strong>Step First</strong>: Create a free Heroku account by going to <code>https://www.heroku.com/</code> and then going to the chatwoot GitHub repository and clicking the <code>Deploy to Heroku</code> button in the readme section.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154656511-8dfe366d-91f3-4ce6-b62f-e0685f7e5e0c.png" alt="Heroku" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/154667615-9bcbba5d-55a3-4c8a-b424-1fd16f2d5a8c.png" alt="deploy" /></p>
<ul>
<li><strong>Step Second</strong>: After you click that button, you'll be able to see the basic setup that chatwoot has already completed. Give the <code>App name</code> and replace the <code>FRONTEND_URL</code> with the <code>App name</code> you just gave, then click <code>Deploy App</code>.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154667713-39521f5d-1e13-4590-b183-0e91605ea52a.png" alt="installation" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/154667860-ec3bc9a5-1893-4c1f-a6e5-b947f53aee48.png" alt="URL config" /></p>
<ul>
<li><strong>Step Third</strong>: Depending on your PC, network status, and server location, the program may take 10 to 15 minutes to install.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154668003-faacf254-27b6-4d62-b423-7c966c8b96fd.png" alt="deploying" /></p>
<ul>
<li><strong>Step Fourth</strong>: After the app has been deployed, go to the settings panel in the dashboard.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154668111-b7143eaa-949e-4e68-b359-2efbe96dd5f9.png" alt="settings" /></p>
<ul>
<li><strong>Step Fifth</strong>: The domain section can be found in the settings menu. In a new window, open that URL. Finally, you've configured chatwoot in Heroku successfully.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154668214-c0cb9408-f40c-46bc-aa22-c94bb03b449b.png" alt="domain" /></p>
<ul>
<li><strong>Step Sixth</strong>: Inside the Resources section, make sure the <code>web</code> and <code>worker</code> resources are enabled.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154669168-ca27814f-0246-47e7-9043-2ca2f597decc.png" alt="Resource section" /></p>
<ul>
<li><strong>Step Seventh</strong>: You should be able to log onto your chatwoot account if everything went smoothly.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154668422-8193c13b-c929-45f8-a2dc-9ab03d0db75d.png" alt="login" /></p>
<p>So, your first account has been created successfully.The main benefit of deploying chatwoot on Heroku is that you have full control over your entire application and your entire data.</p>
<h4 id="heading-chatwoot-cloud-setup">Chatwoot cloud setup</h4>
<p>There is another way to get started with <a target="_blank" href="https://www.chatwoot.com/">chatwoot</a> which is the cloud way so this is the most straightforward way to get started is to register directly on the chatwoots <a target="_blank" href="https://www.chatwoot.com/">website</a>.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/154645706-797c98f2-6a4b-4103-bacd-2f62e661ce2f.png" alt="chatwoot" /></p>
<ul>
<li><strong>Step First</strong>: Fill out all of the required information to create an account.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154647221-b2c786ff-becf-4793-90a3-2d407d475982.png" alt="Sign up" /></p>
<ul>
<li><strong>Step Second</strong>: You'll get an email asking you to confirm your account after you've signed up.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154648298-2f3e1115-e08c-47c6-a718-f53815971f6a.png" alt="Account Confirm" /></p>
<ul>
<li><strong>Step Third</strong>: Proceed to login after you've confirmed your account by clicking the "Confirm my account" option.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154648416-31972c34-a9e7-4c8e-b546-6f8c23a6cf73.png" alt="Login" /></p>
<ul>
<li><strong>Step Fourth</strong>: You may now visit the Chatwoot dashboard and begin connecting it with plethora of platform (websites, Facebook, Twitter, etc.).</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154648980-c1e6330a-3b59-4eae-a0a6-67a9bdb9bf3a.png" alt="Chatwoot dashboard" /></p>
<h5 id="heading-chatwoot-cloud-configuration">Chatwoot Cloud Configuration</h5>
<ul>
<li><strong>Step First</strong>: Let's set up an inbox. The inbox channel acts as a communication hub where everything can be managed, including live-chat, a Facebook page, a Twitter profile, email, and WhatsApp.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154649555-f612e58f-c8f6-409f-9489-923dd21faa24.png" alt="inbox channel" /></p>
<ul>
<li><strong>Step Second</strong>: Now, configure a website and domain name, as well as all of the heading and tagline information like shown below</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154650303-51d77789-1b5e-4c0c-a6ef-183f4f37101e.png" alt="Website Domain" /></p>
<ul>
<li><strong>Step Third</strong>: Finally, to control your mailbox, add "Agents." Keep in mind that only the "Agents" who have been authorized will have full access to the inbox.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154650376-71e0d61c-8186-4e3f-8d25-eba2384ccde3.png" alt="agents" /></p>
<ul>
<li><strong>Step Fourth</strong>: Blammmm!. The website channel has been created successfully.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/37651620/154650930-c24a192f-b86a-4f6a-92eb-99222a2faecc.png" alt="website channel code" /></p>
<p>The website channel must now be connected. Simply copy and paste the entire javascript code provided by chatwoot.Now, head back to our react app and create a new <code>component</code> folder and inside that folder create a new file/component called <code>ChatwootWidget</code> and inside it create a script which helps to loads the Chatwoot asynchronously. Simply follow the exact same steps outlined in the following code below.</p>
<pre><code class="lang-js"><span class="hljs-comment">// ChatwootWidget.js</span>
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> ChatwootWidget = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Add Chatwoot Settings</span>
    <span class="hljs-built_in">window</span>.chatwootSettings = {
      <span class="hljs-attr">hideMessageBubble</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">position</span>: <span class="hljs-string">"right"</span>,
      <span class="hljs-attr">locale</span>: <span class="hljs-string">"en"</span>,
      <span class="hljs-attr">type</span>: <span class="hljs-string">"expanded_bubble"</span>,
    };

    (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">d, t</span>) </span>{
      <span class="hljs-keyword">var</span> BASE_URL = <span class="hljs-string">"https://app.chatwoot.com"</span>;
      <span class="hljs-keyword">var</span> g = d.createElement(t),
        s = d.getElementsByTagName(t)[<span class="hljs-number">0</span>];
      g.src = BASE_URL + <span class="hljs-string">"/packs/js/sdk.js"</span>;
      g.defer = <span class="hljs-literal">true</span>;
      g.async = <span class="hljs-literal">true</span>;
      s.parentNode.insertBefore(g, s);
      g.onload = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">window</span>.chatwootSDK.run({
          <span class="hljs-attr">websiteToken</span>: <span class="hljs-string">""</span><span class="hljs-comment">// add you secret token here,</span>
          <span class="hljs-attr">baseUrl</span>: BASE_URL,
        });
      };
    })(<span class="hljs-built_in">document</span>, <span class="hljs-string">"script"</span>);
  }, []);

  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ChatwootWidget;
</code></pre>
<p>The best part about chatwoot is that you can customize it to your liking. For example, you can modify the position of the floating bubble, extend it, change the language, and hide the message bubble. All it takes is the addition of the following line of code.</p>
<pre><code class="lang-js"><span class="hljs-built_in">window</span>.chatwootSettings = {
  <span class="hljs-attr">hideMessageBubble</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">position</span>: <span class="hljs-string">"right"</span>,
  <span class="hljs-attr">locale</span>: <span class="hljs-string">"en"</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">"expanded_bubble"</span>,
};
</code></pre>
<p>Finally, it's time to import the ChatwootWidget component into our <code>_app_.js</code> file. To do so, simply navigate to the <code>_app_.js</code> file and import the chatwoot widget, then render that component. Your final code of <code>_app_.js</code> should look like this.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// _app.js.js</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/globals.css"</span>;
<span class="hljs-keyword">import</span> { Toaster } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> ChatwootWidget <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ChatwootWidget"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ChatwootWidget</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<p>Now that you've completed the chatwoot integration, your finished project should resemble something like this.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/159338768-74294b10-5ed6-474f-973c-2d26ecd1b467.png" alt="Demo" /></p>
<p><img src="https://user-images.githubusercontent.com/37651620/159338798-54c1f63b-ad86-4a7e-a2d4-587c43c98365.png" alt="Demo" /></p>
<h2 id="heading-deploying-to-netlify">Deploying to netlify</h2>
<p>First, sign in to netlify or create an account if you don't already have one.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248728-38468ed9-241f-4ff3-ba25-45ee73725551.png" alt="Demo" /></p>
<p>You can also log in using a variety of other platforms.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248732-24493114-228d-4217-b195-393a530bf858.png" alt="Demo" /></p>
<p>Import your project from github now.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248905-77307916-5989-46a3-81d1-3624979421a9.png" alt="Demo" /></p>
<p>Sign-in and connect to your GitHub account.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248911-5811b5f6-dd33-4fbb-acd2-184e258a5a1b.png" alt="Demo" /></p>
<p>Look for your project on Github.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248916-532e28de-66c8-4994-8a40-706715c48cbd.png" alt="Demo" /></p>
<p>Add all of the configuration, and don't forget to include the environment variables.</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160248990-2216e8d3-f47a-4b6f-a989-79fe64f3493e.png" alt="Demo" /></p>
<p>Yayyy!! 🎉 🎉 Its deployed on Netlify!</p>
<p><img src="https://user-images.githubusercontent.com/37651620/160249677-65e73965-77b8-45c6-b7fd-afb1a06e4c1a.png" alt="Demoo" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Congratulations 🎉 🎉!!. You've successfully created a fullstack application with Next.js, Supabase, Prisma and chatwoot.This article may have been entertaining as well as instructive in terms of creating a fully fgledged working ecommerce site from absolute scratch.</p>
<p>Aviyel is a collaborative platform that assists open source project communities in monetizing and long-term sustainability. To know more visit Aviyel.com and find great blogs and events, just like this one! Sign up now for early access, and don't forget to follow us on our socials</p>
<h1 id="heading-refrences">Refrences</h1>
<ul>
<li><a target="_blank" href="https://www.prisma.io/docs/guides/development-environment/environment-variables/managing-env-files-and-setting-variables#manage-env-files-manually">Managing .env files and setting variables</a></li>
<li><a target="_blank" href="https://daily-dev-tips.com/posts/a-first-look-at-prisma-studio/">A first look at Prisma Studio</a></li>
<li><a target="_blank" href="https://nextjs.org/learn/basics/data-fetching/two-forms">Pre-rendering and Data Fetching</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-schema/data-model#scalar-fields">Data Model</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client">Generating the client</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/instantiate-prisma-client">Instantiating the client</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/concepts/components/prisma-schema">Prisma schema</a></li>
<li><a target="_blank" href="https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#model-fields">Prisma schema reference</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Web Scraping with NodeJS: a comprehensive guide [part-1]]]></title><description><![CDATA[This blog is about the Node js course on web scraping, it is divided into three-part series, where you will learn how to scrape any type of website and by using a real-world example. This blog will teach you strategies and practices that you won't fi...]]></description><link>https://pramitmarattha.com.np/web-scraping-with-nodejs-a-comprehensive-guide-part-1</link><guid isPermaLink="true">https://pramitmarattha.com.np/web-scraping-with-nodejs-a-comprehensive-guide-part-1</guid><category><![CDATA[Node.js]]></category><category><![CDATA[web scraping]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Wed, 19 Jan 2022 08:47:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1642581975929/MFb_aiOSH.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This blog is about the Node js course on web scraping, it is divided into three-part series, where you will learn how to scrape any type of website and by using a real-world example. This blog will teach you strategies and practices that you won't find anywhere else. You'll be able to quickly grasp all of the ideas and move from the examples and also, you will be able to make your scraper by the end. This blog post is aimed to assist anyone interested in learning web scraping with NodeJS because the issue with any other blog tutorials is a little challenging and you don't always find everything you need in one place.</p>
<h2 id="heading-requirements">Requirements</h2>
<p>The sole and only requirement you need is that you have to have a basic understanding of Javascript or are at least familiar with it, as this will be the only programming language we are going to utilize. I would also recommend reviewing the async and await syntax in es6 and higher, as we'll be using it a lot.</p>
<h2 id="heading-tools">Tools</h2>
<p>Also, if you're wondering what sorts of tools we will be using then, we will be utilizing vscode which is a free code editor that also supports NodeJS debugging without the need to install extra complicated plugins. We'll also utilize a variety of libraries, as well as different libraries, but we'll mostly use puppeteer, which was built and is maintained by the Google team, and also we will be using NighmareJS as well.</p>
<h2 id="heading-tools-and-project-setup">Tools and Project Setup.</h2>
<p>Before we begin creating our scraper program, we must first set up our environments by downloading our editors and NodeJS, as well as complete some basic project setups before we can begin writing code. So first, go to the official VS code website,<a target="_blank" href="https://code.visualstudio.com/">code.visualstudio.com</a>, and download and install the VS code editor which is available free of charge. The key reason to use Visual Studio Code is that it is free and comes with a built-in debugger for Nodejs, making debugging a hundred or even thousand times easier.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nj4f87kbkn1iqdyyfkq9.png" alt="VS code editor" /></p>
<p>After installing our VS code editor, we must ensure that we have Nodejs installed to run our Nodejs application on our machine. Nodejs can be downloaded from nodejs.org and is compatible with both macOS and Windows, with a simple installation process. All you need to do now is download the package and follow the simple installation instructions.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lzvtj0rjyksx09mglwe.png" alt="NodeJs Installation" /></p>
<p>Also, if you want to see what version of Nodejs you have installed, go to the terminal/command line and type <code>node -v</code> which will tell you what version of Nodejs is currently installed on your computer. If this command doesn't work, make sure you restart your computer after installing Nodejs.</p>
<p>Now that you've completed this, go to our VScode and open an empty folder in it, then open the terminal inside it and run the <code>npm init -y</code> command to initialize our project. So now you can see that a new "package.json" file has been produced within that folder, and we can just start installing and using our libraries right away and start making use of them. Also, inside that folder, create a new file called index.js, which will be our entry file, and now we're ready to write some code inside it. This is how your file structure should now look.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyqhm2k39yvyy0j92go8.png" alt="File structure" /></p>
<h2 id="heading-simple-imdb-movie-scraper">Simple IMDB movie scraper.</h2>
<p>We'll be building a simple IMDB scraper that parses the data from the IMDB movie page. This is just one of many real-world examples we've included in this particular section of the blog to give you gist and an idea of what can be accomplished in a short amount of time, so don't worry about getting too many details in this example because we'll go into more depth in the upcoming examples.</p>
<p>So we'll use NodeJS to send a direct request to the IMDB website and expect a response that looks exactly like the image below. To begin, navigate to the IMDB website, right-click, and then select <code>View page source.</code></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rcpslxezm3jins4374s.png" alt="View page source" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2shzlua3svmo6j0k0402.png" alt="Page source" /></p>
<p>As you can see, this is the exact HTML content with Javascript and CSS that we will scrape using our NodeJS scraper. Following that, we will use Cheerio JS, a Nodejs library that can handle HTML content and has a syntax that is nearly identical to jQuery. It would be preferable if you were already familiar with the jQuery syntax. To begin, we must import both the request-promise library, which is in charge of managing requests to the IMDB website and the Cheerio JS library, which will be used to parse the HTML contents.</p>
<p>Now, make sure you're in the <code>index.js</code> file that we previously created, and begin importing the actual libraries inside it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"request-promise"</span>);
<span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</span>);
</code></pre>
<p>The next thing we're going to do is go to the IMDB website and copy the URL of whatever movie you want because we're going to send the request to that specific URL, so simply create a variable named <code>URL</code> and paste that specific copied URL link inside it.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g6vcp3ojwkgvhidbjty9.png" alt="href link" /></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> URL = <span class="hljs-string">"https://www.imdb.com/title/tt0068646/?ref_=fn_al_tt_1"</span>;
</code></pre>
<p>Because we cannot write the asynchronous function in the index unless it is declared as async, we must now write the simple async function that will be accessed when the NodeJS scrapper is fired. Simply create a nameless asynchronous function that will be executed automatically. Before we write anything inside that async function, we must first install the <code>request-response</code> and <code>cheerio</code> libraries. To do so, go to the terminal and type the following command.</p>
<pre><code class="lang-bash">npm install cheerio request-promise
</code></pre>
<p>After installing the package, it should look something similar to this.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6x1da9uv2xxmxaed3jf.png" alt="Package Installation" /></p>
<p>So, now that we have everything installed and ready to go, we can use the request library. To do so, create a variable called response and inside it simply wait for the request to be completed while also passing the URL as its parameters. To test the response, simply console log it; we should be able to see the raw response. So, to run it, go to the debugging tab and press the run button.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4lblow5tu7a0fu9wyd0.png" alt="Debugging and running" /></p>
<p>As you can see, it worked; we got what we needed, which means the script was successful, and we can now begin passing our response to the cheerio library and using it to go through each of the HTML properties and find out exactly what we need.</p>
<p>First, let's get rid of the console log and implement the cheerio library.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> $ = cheerio.load(response);
</code></pre>
<p>We simply created a <code>$ (dollar)</code> variable responsible for the cheerio with the actual IMDB response. Now we can begin writing the scraping for the movie title. First, go to the movie that you want to scrap. So, right-click on the title and select Inspect Element.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmfw55g6jpx7k14gcmt5.png" alt="Inspect element" /></p>
<p>Then we have the div element and inside it, there is an h1 as well as span element, which contains the title of the movie as well as the ratings of the movie. We can select the element by using the jQuery syntax-like selector as shown in the code below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> title = $(<span class="hljs-string">"section.ipc-page-section &gt; div &gt; div &gt; h1"</span>).text();
<span class="hljs-keyword">let</span> rating = $(
    <span class="hljs-string">"div.ipc-button__text &gt; div &gt; div:nth-child(2) &gt; div &gt; span"</span>
  ).text().slice(<span class="hljs-number">0</span>,<span class="hljs-number">6</span>);
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`"<span class="hljs-subst">${title}</span>" movie has an IMDB rating of <span class="hljs-subst">${rating}</span>`</span>);
</code></pre>
<p>If you select the debug option again, you should see something similar to this.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cq6l95s1j71lmjnwgxd.png" alt="Debug" /></p>
<p>So, now that you have enough information to get started with web scraping, let's delve into much more detail.</p>
<h2 id="heading-why-and-when-should-you-scrape-a-website">Why and when should you scrape a website?</h2>
<p>So, before you begin creating a scrapper for your website, you should ask yourself</p>
<ul>
<li>"What data do I need from that particular website ?", </li>
<li>"Do they have an API for that? ", </li>
<li>"Do they provide all the information that I need ?",</li>
<li>"Do they have any limitations that will stall your results ?",</li>
<li>"Do I have to pay to send the request to their server ?"</li>
</ul>
<p>So, if you ever find yourself in a situation like this, where you believe you will not benefit from an official API due to the reasons stated above, or if there is a specific website that does not even have an API, you should consider creating a scrapper.  </p>
<p>What we did previously is a perfect example, where we wrote a straightforward IMDB scrapper. Because IMDB does not have an official API that is accessible to the public, we relied on scraping the data. Of course, the scrapper that we wrote is very basic, but it demonstrated the possibility and power of scrapping with Nodejs. To give you a hot tip, we will explore the IMDB scrapper and write an even more complex scrapper later on.</p>
<p>Before we begin, we must understand when it is appropriate to scrape data from a website. Keep in mind that web scraping is not always an ethical solution, nor is it always a black hat solution; it falls somewhere in the middle. That is to say, web scraping is not illegal, but it can get you in trouble if you violate someone else's website or organizational policies. So, before you plan to scrape a website, you should look at the terms and services of that particular website and see if they have anything related to scraping the data from their website; if they do, it means they may not want you to do it, and if they don't, it means they don't care if you scrape their website or not. Also, before you scrape, you should ask for permission to scrape it. Also, before you start scraping other people's or companies' websites, you should respect their data by using official APIs whenever possible, not spamming their website with an excessive number of requests, and finally, if you want to monetize the scrapped data, always seek legal advice and make sure what you're doing with it is completely legal.</p>
<h2 id="heading-the-most-significant-issue-with-scraping">The most significant issue with scraping</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ub45ebp6dfpc0b5pqffr.png" alt="crawler" /></p>
<p>The most difficult and inconvenient aspect of web scraping is the maintenance and stability of the scrapper. These are the issues that you may have to deal with when building a scrapper. Scrapers can be useful for a variety of things such as extracting data, parsing, and so on. Let's say you wrote a scrapper and it works fine until it doesn't and you encounter some random error, which is exactly the problem, so it can work for one day, one month, or even one year before failing. The main issue with this is that the website that you are currently scraping can constantly change, its structure can change, and their system can change, and also the URLs of the website As a result, you have no control over it, and your scrapper may fail at any time due to this issue. When writing or coding scrappers, the logic and workflow are based on the current website you are attempting to scrape and its structure, so if the website decides to change its entire structure, you may have to change the entire structure as well as the logic of the scrapper as well. Of course, if you still want to make it work, you may be wondering how to solve this type of problem. The short answer is that you cannot change this type of problem because you have no control over the website you are attempting to scrape; you must simply deal with the problem that arises. This is why you must learn how to develop a scrapper quickly and efficiently, as well as how to debug and fix problems. This type of problem can occur on both a small and large scale, so you must be prepared at all times.</p>
<h2 id="heading-request-method-with-the-assistance-of-the-request-library">Request Method with the assistance of the Request Library</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vctapewbovqi5uewg5be.png" alt="request-promise" /></p>
<p>In this section, we'll go over the request-promise library, what you can do with it, and when it's best to use it. So, what exactly are we able to do with the request library? We're incorporating this library into our earlier project that we did. We use this library because the <code>request</code> library allows us to submit requests to the server in the simplest and fastest way possible. Before we begin, let's look at some examples. So, when you visit a website, a basic GET request to the server is sent first, followed by the initial content, the HTML response. So, with the request library, you can do the same thing, but instead of using the browser, you can write the action in Nodejs and it will do everything for you. </p>
<p>Let's take another example: when you want to login and enter your username and password into a specific website, a POST request is sent to the server, which sends the details of your entered account to the server for confirmation. This can also be done manually in Nodejs by simulating every or any request the browser makes to any website; all we have to do is provide the right parameters to it. In the case of the IMDB scraper, we used it as a GET request to obtain HTML and parse it.</p>
<h2 id="heading-benefits-and-drawbacks-of-request-library">Benefits and Drawbacks of Request Library</h2>
<p>Since you control every parameter that you send to the server, it can be a little overwhelming at times. Let's use the previously described login process as an example. So, as previously described, the login process can consist of a single simple POST request to the server with the username and password depending on the website, followed by a single response with some cookies or a token in such case the request method is ideal, or the login system can consist of multiple requests on a simple login form on some websites can automatically send multiple requests for security reasons or because of how they were originally built on and In that case, you do not want to use the request library but of course, it is feasible, but it is very time-consuming and can be extremely frustrating, and many things can go wrong, such as missing simple parameters in the request headers and the server you are currently attempting to reach refuses to accept it. It all depends on the situation, but it is strongly discouraged to use this library if you have a large number of requests to send. Hence, if the website is more complex and automatically sends AJAX requests with different parameters and tokens, the best method would be to use the headless browser, which we will cover in detail in the following upcoming sections. </p>
<p>Therefore, only in simpler times, you should use the request library, but when the website has loads of security behind it and is dynamically rendered, you should probably use another method or even a headless browser method.</p>
<h2 id="heading-scraping-with-a-browser-automation-approach">Scraping with a browser automation approach</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5x4h8i2edzqhyaosf83f.png" alt="scraping approach" /></p>
<p>In this section, we'll deep dive into browser automation and how it might be applied for developing a scraper. But first, let's define browser automation. Browser automation, in our case with the help of NodeJs, essentially means controlling the browser using code. Now that you know that certain browser engines support this, you can see that you can't just automate your regular browser; instead, you'll need a browser that allows you to manage it using code, and we'll look at a plethora of examples in the upcoming topics ahead.</p>
<h2 id="heading-benefits-and-drawbacks-of-employing-browser-automation">Benefits and drawbacks of employing browser automation.</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g19huqro8pfdim2v1zmj.png" alt="pros and cons" /></p>
<p>Before we get started, let's quickly go over the benefits and drawbacks of using Browser automation. For starters, it's much more beginner-friendly, and it's very easy to understand the action of the steps that you need to take because they're the same as when you browse the internet; all you have to do is write the specific code and scripts that your automated browser will follow. In most circumstances, implementing the scrapper with the automated browser is much cleaner, and you may wind up writing less code than you would with the request approach, but this, of course, depends on the page that needs to be scraped and what you need from it. The first disadvantage of this request approach is that you are essentially relying on the API availability of the individual browser you are automating. Others browsers have limited capabilities, and some aren't very stable, and some aren't even updated anymore, which is why you should be cautious and thoroughly study the browser before using it in your scrapper. So, before you decide whatever type of browser you want to automate, the browser's documentation will usually give detailed information.</p>
<h2 id="heading-when-is-it-appropriate-to-use-browser-automation-for-a-scraping-project">When is it appropriate to use browser automation for a scraping project?</h2>
<p>To begin, you must understand that there is no right or incorrect option. Any website may be done using requests, and the other way around. It all depends on how long it will take, how much code you will write, and how successful it will be. The browser automated scrapper will use more bandwidth and resources to load the page content from the website than the request method because the browser will load every CSS file, every javascript file, and every image that is on the website, whereas the request method will only get the HTML code for the website itself and will not load the external contents like files and libraries. So, if bandwidth and a few milliseconds of delay aren't important to you, browser automation is an excellent and perfect option for you. Browser automation makes things a lot easier while also saving you a lot of time.</p>
<h2 id="heading-browser-automation-libraries">Browser automation libraries</h2>
<p>Before you begin, you must first decide which libraries to use. There are two excellent libraries available: Puppeteer and NightmareJS. There are many more libraries, although many of them are closed or abandoned.
Puppeteer is built on the Chrome browser and is also known as a headless version of Chrome. It was created specifically for automation, testing, and testing chrome extensions, among other things, but in our case, we will be using this library for scraping. This library is developed and maintained by the Google Chrome team and is a fully functional and up-to-date headless browser.
NightmareJS, on the other hand, is the electron browser's driver. It's a lot of fun to learn and even more fun to use, but it's not particularly suitable for complex scrappers. When compared to the puppeteer library, it has a lot of limitations. One of the library's biggest flaws is that it doesn't allow numerous tabs and links to open at once. As a result, libraries like this may break your scrapper or drive you to make compromises when you need them.</p>
<p>So, before you start scraping, let's go over a few things you might need to know. When you're running the scrapper and testing it, you can turn on the visual browser to see each action as it happens in real-time. This helps you understand and debug when you have a problem or when you're building a new scrapper. A competent headless browser will provide you with practically all APIs, allowing you to automate almost everything a user can do but by using the power of only coding and programming.    </p>
<h2 id="heading-imdb-scraper-using-a-request-method">IMDB scraper using a request method</h2>
<p>In this segment of the course, we'll delve a little deeper into the IMDB scraper that we constructed in the first session. We'll make it a little more complex as we go, and we'll learn new things along the way. With the request method, we'll learn how to spoof or fake user headers. So the main question is "why do we need to spoof them?" It's because we want it to appear that the scraper is a browser that's making the request. Request headers are extra parameters that the browser sends to the server automatically. They usually contain cookie information, such as whether you're logged in or not, and other types of browser information.
So, let's get started with how to check these. First, open the browser and right-click to open the developer tools. Right now, we need to go to the network tab to see all of the requests that are happening in this tab.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hp3kden2ubq9ti2xvw1o.png" alt="Network Tab" /></p>
<p>We may see a number of requests and their types here. There's the document, as well as images, graphics, style sheets, javascript, and a whole lot more.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9cosmv5u7192zb7m4j3.png" alt="Network Tab" /></p>
<p>Let's take a look at the initial request that's being made, as you can see here. We can see the general information and the response headers, but we need to look at the request headers, which are a little farther down. Now we need to go to GitHub's request promise website and look at their documentation to see how we can include those in our request.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdlf85a74yjs76m94m1k.png" alt="request-promise" /></p>
<p>Here =&gt; <a target="_blank" href="https://github.com/request/request-promise">https://github.com/request/request-promise</a></p>
<p>What we need to look for is a way to add those extra parameters throughout the request, and if we look closely enough, we'll see the header options.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hed6dyl5u3tfamueil50.png" alt="header" /></p>
<p>We'll copy the header and paste it into our VS code editor. Right now, we only have the URL as a parameter, and we need to alter it so it's an actual object, so delete the URL and build an object, but we'll still need to input the URI URL and then paste in the headers option.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"request-promise"</span>);
<span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</span>);
<span class="hljs-keyword">const</span> URL = <span class="hljs-string">"https://www.imdb.com/title/tt0068646/?ref_=fn_al_tt_1"</span>;
(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request({
    <span class="hljs-attr">uri</span>: URL,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Request-Promise"</span>,
    },
  });
 <span class="hljs-keyword">let</span> $ = cheerio.load(response);
  <span class="hljs-comment">// console.log(response);</span>
  <span class="hljs-keyword">let</span> title = $(<span class="hljs-string">"section.ipc-page-section &gt; div &gt; div &gt; h1"</span>).text();
  <span class="hljs-keyword">let</span> rating = $(
    <span class="hljs-string">"div.ipc-button__text &gt; div &gt; div:nth-child(2) &gt; div &gt; span"</span>
  ).text().slice(<span class="hljs-number">0</span>,<span class="hljs-number">6</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`"<span class="hljs-subst">${title}</span>" movie has a IMDB rating of <span class="hljs-subst">${rating}</span>`</span>);
})();
</code></pre>
<p>Right now, we have precisely what we had before with the addition of a user parameter to the request with the value request promise. Of course, request promise isn't a user agent, but it's something we can simply adjust based on the documentation provided.</p>
<p>Let's go ahead and obtain the request headers now. Let's go back to the dev tools and look at the first request, making sure it's the one that's responsible for the IMDB page and not an image or a javascript file. Then, just like before, look at the request header and copy everything for now.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7aqppu7p6ecjvlv6yh7.png" alt="Network Tab" /> </p>
<p>Copy everything and return it to the editor. What we have now are the request headers that are sent by the browser when we enter the IMDB page. What we need to do now is convert them all to javascript objects and pass them on instead of the previous useragent. Let's format them properly and replace them, indent them properly. Now we have control over all of the requests that are sent by the browser are being sent by us. Finally, we only need to worry about the cookie because we don't need it in this situation, so let's erase it, and we're done. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">const</span> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"request-promise"</span>);
<span class="hljs-keyword">const</span> cheerio = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cheerio"</span>);
<span class="hljs-keyword">const</span> URL = <span class="hljs-string">"https://www.imdb.com/title/tt0068646/?ref_=fn_al_tt_1"</span>;
(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request({
    <span class="hljs-attr">uri</span>: URL,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"accept"</span>:
       <span class="hljs-string">"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"</span>,
      <span class="hljs-string">"accept-encoding"</span>: <span class="hljs-string">"gzip, deflate, br"</span>,
      <span class="hljs-string">"accept-language"</span>: <span class="hljs-string">"en-IN,en-US;q=0.9,en;q=0.8"</span>,
      <span class="hljs-string">"cache-control"</span>: <span class="hljs-string">"no-cache"</span>,
      <span class="hljs-string">"pragma"</span>: <span class="hljs-string">"no-cache"</span>,
      <span class="hljs-string">"sec-ch-ua"</span>:
        <span class="hljs-string">'" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"'</span>,
      <span class="hljs-string">"sec-ch-ua-mobile"</span>: <span class="hljs-string">"?1"</span>,
      <span class="hljs-string">"sec-ch-ua-platform"</span>: <span class="hljs-string">"Android"</span>,
      <span class="hljs-string">"sec-fetch-dest"</span>: <span class="hljs-string">"document"</span>,
      <span class="hljs-string">"sec-fetch-mode"</span>: <span class="hljs-string">"navigate"</span>,
      <span class="hljs-string">"sec-fetch-site"</span>: <span class="hljs-string">"same-origin"</span>,
      <span class="hljs-string">"sec-fetch-user"</span>: <span class="hljs-string">"?1"</span>,
      <span class="hljs-string">"sec-gpc"</span>: <span class="hljs-string">"1"</span>,
      <span class="hljs-string">"upgrade-insecure-requests"</span>: <span class="hljs-string">"1"</span>,
      <span class="hljs-string">"user-agent"</span>:
        <span class="hljs-string">"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Mobile Safari/537.36"</span>,
    },
  });
  <span class="hljs-keyword">let</span> $ = cheerio.load(response);
  <span class="hljs-comment">// console.log(response);</span>
<span class="hljs-keyword">let</span> title = $(<span class="hljs-string">"section.ipc-page-section &gt; div &gt; div &gt; h1"</span>).text();
<span class="hljs-keyword">let</span> rating = $(
    <span class="hljs-string">"div.ipc-button__text &gt; div &gt; div:nth-child(2) &gt; div &gt; span"</span>
  ).text().slice(<span class="hljs-number">0</span>,<span class="hljs-number">6</span>);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`"<span class="hljs-subst">${title}</span>" movie has a IMDB rating of <span class="hljs-subst">${rating}</span>`</span>);
})();
</code></pre>
<p>Now we have the user agent, which is specific to the computer that you're using to code this. You can simply modify this on the user agent and check phoney ones on the internet and paste them right here; you don't need to paste in your actual browser info. Finally, let's put this to the test to see if it still works. Go to the debug tab and select debug play.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xsh050puih9ta52e96mv.png" alt="Debugger" /></p>
<p>Now, let's hope for the best and head to the debug console, where you can see that it does not work, as it does not print the movie's title or rating. So, we'll use what we learned before and set a debugger right at the console.log line to see what's going on. Let's run it again, and it stops right at the console.log line, and we can see what variables we have. We have the rating, which is an empty string, and the title, which is also an empty string, which means it didn't find the selectors we were looking for because the response changed, as you can see and it is completely nonsensical.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0z392r040n9di3co2vy.png" alt="response" /></p>
<p>So, when we requested with only the URL, all of the other options were default, but now that we've added our own, everything is the default. We get this response because we forgot to add the gzip option to some of the default parameters for the request function.</p>
<p>Follow <a target="_blank" href="https://bit.ly/3Gb2gxq">@aviyelHQ</a> or <a target="_blank" href="https://bit.ly/3FaSt9d">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Join Aviyel's Discord =&gt; <a target="_blank" href="https://discord.gg/TbfZmbvnN5">Aviyel's world</a></p>
<p>Twitter =&gt;<a target="_blank" href="https://bit.ly/3Gb2gxq">https://twitter.com/AviyelHq</a></p>
]]></content:encoded></item><item><title><![CDATA[Building a MERN stack simple blog site from absolute scratch]]></title><description><![CDATA[Even a few years ago, web application development was not what it is today. Nowadays, there are so many options that the uninitiated are frequently perplexed as to what is best for them. This applies not only to the overall stack but also to the deve...]]></description><link>https://pramitmarattha.com.np/building-a-mern-stack-simple-blog-site-from-absolute-scratch</link><guid isPermaLink="true">https://pramitmarattha.com.np/building-a-mern-stack-simple-blog-site-from-absolute-scratch</guid><category><![CDATA[React]]></category><category><![CDATA[MERN Stack]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Thu, 02 Dec 2021 11:48:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638445592958/f3zw0-t_Ol.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Even a few years ago, web application development was not what it is today. Nowadays, there are so many options that the uninitiated are frequently perplexed as to what is best for them. This applies not only to the overall stack but also to the development tools; there are so many options. This blog tutorial asserts that the MERN stack is ideal for developing a full web application, and it walks the reader through the entire process in a very detailed manner.</p>
<p>So, what exactly is the MERN stack?</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jefqqo977czycwrg0zz.png" alt="MERN stack" /></p>
<p>The MERN stack is a popular set of technologies for creating a modern Single Page Application (SPA). MERN stands for MongoDB, Express, React, and Node.js:</p>
<ul>
<li><p><strong><em>Node.js</em></strong> is a popular server-side framework that allows us to run JavaScript code on a web server.</p>
</li>
<li><p><strong><em>Express</em></strong> is a Node.js web application framework that makes Node application development simpler and faster.</p>
</li>
<li><p><strong><em>MongoDB</em></strong> is a NoSQL database that stores data persistently in the form of collections and documents.</p>
</li>
<li><p><strong><em>React</em></strong> is a JavaScript frontend library for creating user interfaces.</p>
</li>
</ul>
<p>In this blog tutorial, we will create a full-stack blog application that performs CRUD operations by utilizing the MERN stack. This blog tutorial should help you understand the fundamental operations of the MERN stack.</p>
<p>Here is our application's final sneak peek.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635957501821-image-resized.png" alt="Demo" /></p>
<h2 id="heading-setting-up-the-backend">Setting up the backend</h2>
<p>Create a two folder name client and server inside your project directory, then open it inside the Visual Studio Code or any code editor of your choice.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1t3zl6rmhak1tlbwr0ia.png" alt="Making Directory" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635829814932-image.png" alt="Client and Server directory" /></p>
<p>Now, we'll begin by configuring our backend with npm and installing necessary packages, followed by configuring a MongoDB database, configuring a server with Node and Express, designing a database schema to define our Blog, and configuring API routes to create, read, update, and delete blog data and information from the database. so, now navigate to your server's directory and run the code below from the command prompt.</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<h3 id="heading-updating-packagejson">Updating package.json</h3>
<p>To install the dependencies, execute the following commands in the terminal.</p>
<pre><code class="lang-bash">npm install cors express dotenv mongoose nodemon body-parser
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635830732367-image-resized.png" alt="Dependencies" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hre0aatrntktxjcvqy9w.png" alt="Package Installed" /></p>
<p>The "package.json" file should look like this after the dependencies have been installed.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1636000163820-image-resized.png" alt="Package json" /></p>
<p>And also, remember to update the scripts and type as well.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bidmnw55ciqfdyr0jdo9.png" alt="Script and Types" /></p>
<p>Now, navigate to your server directory and create a server.js file within it.</p>
<h3 id="heading-configuring-serverjs">Configuring server.js</h3>
<ul>
<li><p>Import express module.</p>
</li>
<li><p>Import bodyParser module</p>
</li>
<li><p>Import mongoose module</p>
</li>
<li><p>Import CORS module</p>
</li>
<li><p>Use express() to start our app.</p>
<p>```javascript
//server.js
import express from "express";
import bodyParser from "body-parser";
import mongoose from "mongoose";
import cors from "cors";</p>
</li>
</ul>
<p>const app = express();</p>
<pre><code>Now we can use <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> the different methods <span class="hljs-keyword">on</span> that app instance. First, let<span class="hljs-string">'s do some general setup. We'</span>ll use app.use <span class="hljs-keyword">and</span> simply pass the bodyParser <span class="hljs-keyword">and</span> <span class="hljs-keyword">limit</span> it <span class="hljs-keyword">by</span> <span class="hljs-number">20</span> <span class="hljs-keyword">to</span> <span class="hljs-number">50</span>mb because w<span class="hljs-string">e're sending some images that can be very large in size, and we'</span>ll <span class="hljs-keyword">also</span> specify the extended <span class="hljs-keyword">to</span> <span class="hljs-keyword">true</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">do</span> the same thing <span class="hljs-keyword">with</span> the bodyParser URL encoded <span class="hljs-keyword">and</span> pass the same parameter <span class="hljs-keyword">and</span> now we are <span class="hljs-keyword">also</span> going <span class="hljs-keyword">to</span> use the CORS <span class="hljs-keyword">and</span> <span class="hljs-keyword">call</span> it <span class="hljs-keyword">as</span> a <span class="hljs-keyword">function</span>.

```javascript
//<span class="hljs-keyword">server</span>.js
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> "express";
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> "body-parser";
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> "mongoose";
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> "cors";

const app = express();

app.use(bodyParser.json({ <span class="hljs-keyword">limit</span>: <span class="hljs-string">'50mb'</span>, extended: <span class="hljs-keyword">true</span> }))
app.use(bodyParser.urlencoded({ <span class="hljs-keyword">limit</span>: <span class="hljs-string">'50mb'</span>, extended: <span class="hljs-keyword">true</span> }))
app.use(cors());
</code></pre><p>Now it's time to link our server application to the real database, so we'll utilize the MongoDB database, especially the MongoDB cloud Atlas version, which means we'll be hosting our database onto their cloud.</p>
<h3 id="heading-setting-up-mongodb-cloud-cluster">Setting up MongoDB cloud cluster</h3>
<p>MongoDB is a document-oriented database that is open source and cross-platform. MongoDB is a NoSQL database that stores data in JSON-like documents with optional schemas. MongoDB is a database created and distributed by MongoDB Inc. under the provisions of the Server Side Public License.</p>
<p>Official MongoDB website
<img src="https://aviyel.com/assets/uploads/files/1635879960018-image-resized.png" alt="MongoDB cloud" /></p>
<p>Sign in to MongoDB
<img src="https://aviyel.com/assets/uploads/files/1635322431066-image-resized.png" alt="Sign In MongoDB" /></p>
<p>Create a Project
<img src="https://aviyel.com/assets/uploads/files/1635845239627-image-resized.png" alt="Create Projects" /></p>
<p>Adding members
<img src="https://aviyel.com/assets/uploads/files/1635322628029-image-resized.png" alt="Adding Members" /></p>
<p>Building a database
<img src="https://aviyel.com/assets/uploads/files/1635845404948-image-resized.png" alt="Building Database" /></p>
<p>Creating a cluster
<img src="https://aviyel.com/assets/uploads/files/1635322799518-image-resized.png" alt="Creating Cluster" /></p>
<p>Selecting a cloud service provider
<img src="https://aviyel.com/assets/uploads/files/1635322998309-image-resized.png" alt="Service Provider" /></p>
<p>Make a cluster and wait for the cluster to be built before proceeding (usually takes around 5 -10 minutes)
<img src="https://aviyel.com/assets/uploads/files/1635845526968-image-resized.png" alt="Database Deployment" /></p>
<p>Navigate to the network access tab and select "Add IP address."
<img src="https://aviyel.com/assets/uploads/files/1635845708571-image-resized.png" alt="Allow IP address" /></p>
<p>In the database, create a user. You'll need the username and password for the MongoDB URI and finally, create a database user.
<img src="https://aviyel.com/assets/uploads/files/1635323489283-image-resized.png" alt="Creating User" /></p>
<p>Now, select the Choose a connection method.
<img src="https://aviyel.com/assets/uploads/files/1635323638076-image-resized.png" alt="Connection Method" /></p>
<p>Connect your application by clicking on it and finally select the correct driver and version.
<img src="https://aviyel.com/assets/uploads/files/1635323727857-image-resized.png" alt="Connect to cluster" />
<img src="https://aviyel.com/assets/uploads/files/1635851651151-image-resized.png" alt="Cloud Atlas" /></p>
<p>Now, inside server.js create a new variable and name it DB_CONNECTION. Inside it, create a string and simply paste the copied mongo DB connection URL. Now, inside it, enter your username and password, making sure to remove all the brackets and enter your own credentials. We'll secure the credential later by creating environmental variables, but for now, let's add it this way. The second thing we need is a PORT, so simply enter the port number, for now, 6000, and finally, we will use mongoose to connect to our database, so enter mongoose. connect() which is a function with two different parameters. The first will be the DB CONNECTION, and the second will be an object with two different options. The first is useNewUrlParser, which we will set to true, and the second is useUnifiedTopology, which we will also set to true. These objects are not required, but we will see some errors or warnings on our console. Following that, let's chain a.then() and.catch() because this will return a promise, so inside .then() will call the app and invoke listen, which has two parameters, the first of which is PORT and the second of which is the callback function that will be executed if our application is successfully connected and finally, if the connection to the database is not successful we will simply console log our error message.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//server.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> <span class="hljs-string">"body-parser"</span>;
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;
<span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;

dotenv.config();

<span class="hljs-keyword">const</span> app = express();

app.use(bodyParser.json({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span>, <span class="hljs-attr">extended</span>: <span class="hljs-literal">true</span> }));
app.use(bodyParser.urlencoded({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span>, <span class="hljs-attr">extended</span>: <span class="hljs-literal">true</span> }));
app.use(cors());

<span class="hljs-keyword">const</span> DB_CONNECTION = process.env.DATABASE_URL;
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">6000</span>;

mongoose
  .connect(DB_CONNECTION, { <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span> })
  .then(<span class="hljs-function">() =&gt;</span>
    app.listen(PORT, <span class="hljs-function">() =&gt;</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running @ : http://localhost:<span class="hljs-subst">${PORT}</span>`</span>)
    )
  )
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<p>Insert mongodb+srv into the .env file.</p>
<pre><code><span class="hljs-attr">PORT</span>=<span class="hljs-number">4000</span>
<span class="hljs-attr">DATABASE_URL</span>=mongodb+srv://admin:&lt;password&gt;@cluster0.ddtsa.mongodb.net/myFirstDatabase?retryWrites=<span class="hljs-literal">true</span>&amp;w=majority
</code></pre><p>That's it; we've successfully linked our server to the database.</p>
<p>Now that we've successfully connected to our database, let's get started on creating our routes for our backend application. To do so, we'll need to create a new folder inside the server called routes Within the routes folder, we will create a js file called blogPosts.routes.js.</p>
<p>This is what your folder structure should look like.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635880486299-image.png" alt="Folder Structure" /></p>
<p>We are going to add all of the routes inside of blogPosts.routes.js, so first we must import express from "express" and also configure our router. Now we can begin adding our routes to it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// routes/blogPosts.routes.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;

<span class="hljs-keyword">const</span> router = express.Router();

router.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Awesome MERN BLOG"</span>);
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>Let's get started on your server. js file and import the blogPost route. Now we can use express middleware to connect this blogPost to our application</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> <span class="hljs-string">"body-parser"</span>;
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> cors <span class="hljs-keyword">from</span> <span class="hljs-string">"cors"</span>;
<span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>;

<span class="hljs-keyword">import</span> blogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">"./routes/blogPosts.js"</span>;

dotenv.config();

<span class="hljs-keyword">const</span> app = express();

app.use(bodyParser.json({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span>, <span class="hljs-attr">extended</span>: <span class="hljs-literal">true</span> }));
app.use(bodyParser.urlencoded({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span>, <span class="hljs-attr">extended</span>: <span class="hljs-literal">true</span> }));
app.use(cors());

<span class="hljs-comment">// remember to add this after cors</span>
app.use(<span class="hljs-string">"/api/blogs"</span>, blogPosts);

<span class="hljs-keyword">const</span> DB_CONNECTION = process.env.DATABASE_URL;
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">6000</span>;

mongoose
  .connect(DB_CONNECTION, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
  })
  .then(<span class="hljs-function">() =&gt;</span>
    app.listen(PORT, <span class="hljs-function">() =&gt;</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running at: http://localhost:<span class="hljs-subst">${PORT}</span>`</span>)
    )
  )
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(error));
</code></pre>
<p>Before we go any further, let's create a folder structure for our backend applications that will allow them to be much more scalable. So let’s create a new folder called controllers inside the controllers’ folder we are also going to create a file called blogPosts.controller.js .So controllers is simply a file that contains route-specific logic.
so your blogPosts.routes.jsand blogPosts.controller.jsshould resemble something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635913519704-image.png" alt="Folder Structure" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//routes/blogPosts.routes.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;

<span class="hljs-keyword">import</span> { getAllBlogPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../controllers/blogPosts.controller.js'</span>;

<span class="hljs-keyword">const</span> router = express.Router();

router.get(<span class="hljs-string">'/'</span>, getAllBlogPosts);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>blogPosts.controller.js</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//controllers/blogPosts.controller.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;

<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllBlogPosts = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">"Awesome MERN BLOG"</span>);
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>Let's make a new model for our blog posts, so make a folder called models and a file called blogs.js inside it.</p>
<p>The folder structure should resemble something like this</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635913899313-image.png" alt="Folder Structure" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// models/blogs.js</span>
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;

<span class="hljs-keyword">const</span> blogSchema = mongoose.Schema({
  <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">tags</span>: [<span class="hljs-built_in">String</span>],
  <span class="hljs-attr">fileUpload</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">upvote</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-number">0</span>,
  },
  <span class="hljs-attr">creator</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">createdAt</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
  },
});

<span class="hljs-keyword">var</span> BlogPost = mongoose.model(<span class="hljs-string">"BlogArticle"</span>, blogSchema);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> BlogPost;
</code></pre>
<p>Let's start adding more routes now that our model is complete.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// routes/blogPosts.routes.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;

<span class="hljs-keyword">import</span> {
  getAllBlogPosts,
  addBlogPost,
  getSinglePost,
  updateSingleBlogPost,
  removeSingleBlogPost,
  likeBlogPost,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../controllers/blogPosts.controller.js"</span>;

<span class="hljs-keyword">const</span> router = express.Router();

router.get(<span class="hljs-string">"/"</span>, getAllBlogPosts);
router.post(<span class="hljs-string">"/"</span>, addBlogPost);
router.get(<span class="hljs-string">"/:id"</span>, getSinglePost);
router.patch(<span class="hljs-string">"/:id"</span>, updateSingleBlogPost);
router.delete(<span class="hljs-string">"/:id"</span>, removeSingleBlogPost);
router.patch(<span class="hljs-string">"/:id/likeedBlogPost"</span>, likeBlogPost);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>Now, inside the controller's folder, add the following code to your blogPosts.controllers.js file.</p>
<p><strong><em>getAllBlogPosts method fetches all the blogs information.</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllBlogPosts = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> blogPosts = <span class="hljs-keyword">await</span> BlogPost.find();
    res.status(<span class="hljs-number">200</span>).json(blogPosts);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};
</code></pre>
<p><strong><em>addBlogPost method adds/insert only one blog</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title, description, fileUpload, creator, tags } = req.body;

  <span class="hljs-keyword">const</span> createNewPost = <span class="hljs-keyword">new</span> BlogPost({
    title,
    description,
    fileUpload,
    creator,
    tags,
  });

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> createNewPost.save();
    res.status(<span class="hljs-number">201</span>).json(createNewPost);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">409</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};
</code></pre>
<p><strong><em>getSinglePost method fetches single blog post</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getSinglePost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> singlepost = <span class="hljs-keyword">await</span> BlogPost.findById(id);

    res.status(<span class="hljs-number">200</span>).json(singlepost);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};
</code></pre>
<p><strong><em>updateSingleBlogPost method updates single blog posts</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateSingleBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;
  <span class="hljs-keyword">const</span> { title, description, creator, fileUpload, tags } = req.body;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`post <span class="hljs-subst">${id}</span> not found`</span>);

  <span class="hljs-keyword">const</span> updatedBlogPost = {
    creator,
    title,
    description,
    tags,
    fileUpload,
    <span class="hljs-attr">_id</span>: id,
  };
  <span class="hljs-keyword">await</span> BlogPost.findByIdAndUpdate(id, updatedBlogPost, { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> });
  res.json(updatedBlogPost);
};
</code></pre>
<p><strong><em>removeSingleBlogPost method deletes single blog posts</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> removeSingleBlogPost = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`post <span class="hljs-subst">${id}</span> not found`</span>);

  <span class="hljs-keyword">await</span> BlogPost.findByIdAndRemove(id);

  res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Successfully deleted"</span> });
};
</code></pre>
<p><strong><em>likeBlogPost method upvotes the posts</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> likeBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`No post with id: <span class="hljs-subst">${id}</span>`</span>);

  <span class="hljs-keyword">const</span> post = <span class="hljs-keyword">await</span> BlogPost.findById(id);

  <span class="hljs-keyword">const</span> updatedBlogPost = <span class="hljs-keyword">await</span> BlogPost.findByIdAndUpdate(
    id,
    { <span class="hljs-attr">upvote</span>: post.upvote + <span class="hljs-number">1</span> },
    { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> }
  );

  res.json(updatedBlogPost);
};
</code></pre>
<p>Your blogPosts.controller.js should resemble something like this</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// blogPosts.controller.js</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>;
<span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;

<span class="hljs-keyword">import</span> BlogPost <span class="hljs-keyword">from</span> <span class="hljs-string">"../models/blogs.js"</span>;

<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getAllBlogPosts = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> blogPosts = <span class="hljs-keyword">await</span> BlogPost.find();
    res.status(<span class="hljs-number">200</span>).json(blogPosts);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title, description, fileUpload, creator, tags } = req.body;

  <span class="hljs-keyword">const</span> createNewPost = <span class="hljs-keyword">new</span> BlogPost({
    title,
    description,
    fileUpload,
    creator,
    tags,
  });

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> createNewPost.save();
    res.status(<span class="hljs-number">201</span>).json(createNewPost);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">409</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getSinglePost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> singlepost = <span class="hljs-keyword">await</span> BlogPost.findById(id);

    res.status(<span class="hljs-number">200</span>).json(singlepost);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: error.message });
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateSingleBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;
  <span class="hljs-keyword">const</span> { title, description, creator, fileUpload, tags } = req.body;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`post <span class="hljs-subst">${id}</span> not found`</span>);

  <span class="hljs-keyword">const</span> updatedBlogPost = {
    creator,
    title,
    description,
    tags,
    fileUpload,
    <span class="hljs-attr">_id</span>: id,
  };
  <span class="hljs-keyword">await</span> BlogPost.findByIdAndUpdate(id, updatedBlogPost, { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> });
  res.json(updatedBlogPost);
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> likeBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`No post with id: <span class="hljs-subst">${id}</span>`</span>);

  <span class="hljs-keyword">const</span> post = <span class="hljs-keyword">await</span> BlogPost.findById(id);

  <span class="hljs-keyword">const</span> updatedBlogPost = <span class="hljs-keyword">await</span> BlogPost.findByIdAndUpdate(
    id,
    { <span class="hljs-attr">upvote</span>: post.upvote + <span class="hljs-number">1</span> },
    { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> }
  );

  res.json(updatedBlogPost);
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> removeSingleBlogPost = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">if</span> (!mongoose.Types.ObjectId.isValid(id))
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">`post <span class="hljs-subst">${id}</span> not found`</span>);

  <span class="hljs-keyword">await</span> BlogPost.findByIdAndRemove(id);

  res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Successfully deleted"</span> });
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>After restarting the server, you should see something similar to this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635922636145-image.png" alt="Server Running" /></p>
<hr />
<h2 id="heading-configuring-our-frontend">Configuring our Frontend</h2>
<p>We'll start by setting up our frontend first using create-react-app  .We will be creating the UI and its functionalities from the ground up. Let's get started on our application now.</p>
<h2 id="heading-installing-react-application">Installing react application</h2>
<p>Let us begin with the frontend part and craft it using react. So, if Node.js isn't already installed on your system, the first thing you should do is install it. So, go to the official Node.js website and install the correct and appropriate version. We need node js so that we can use the node package manager, also known as NPM.</p>
<p>Now, open client folder inside the code editor of your choice. For this tutorial, I will be using VScode. Next step, let’s open the integrated terminal and type npx create-react-app . this command will create the app inside the current directory and that application will be named as client</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635330282631-image-resized.png" alt="npx script" /></p>
<p>It usually takes only a few minutes to install. Normally, we would use npm to download packages into the project, but in this case, we are using npx, the package runner, which will download and configure everything for us so that we can start with an amazing template. It's now time to start our development server, so simply type npm start, and the browser will automatically open react-app.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635330419245-image-resized.png" alt="Starting React Application" /></p>
<h2 id="heading-react-boilerplate-cleanup">React boilerplate cleanup</h2>
<p>Before we begin building our projects, we must first clean them up by removing some of the files provided by create-react-app. Your src files should look like this after you've cleaned them up.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1634550649379-image.png" alt="Folder Structure" /></p>
<h2 id="heading-installing-some-packages">Installing some packages</h2>
<p>We will need to install a few third-party packages for this project. so copy and paste the following command into your terminal</p>
<pre><code class="lang-bash">npm install @material-ui/core axios moment react-file-base64 redux react-redux redux-thunk
</code></pre>
<p>After installing all these packages your packge.json file should look like this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1636000316508-image-resized.png" alt="Package json" /></p>
<p>After we've installed all of our project's dependencies, let's add two components to it and call them Blogs, BlogPosts and BlogPostsForm.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635924796485-image.png" alt="Folder structure" /></p>
<p>Now that we've got everything set up, let's go over to our App.js file and start writing some code but before that lets create one Assets folder inside our src folder and add the logo image of yor choice. After that, make another folder called styles, and inside it, make a file called app.styles.js, and paste the following code inside it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/styles/app.styles.js</span>
<span class="hljs-keyword">import</span> { makeStyles } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core/styles"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> makeStyles(<span class="hljs-function">() =&gt;</span> ({
  <span class="hljs-attr">navigationBar</span>: {
    <span class="hljs-attr">borderRadius</span>: <span class="hljs-number">10</span>,
    <span class="hljs-attr">margin</span>: <span class="hljs-string">"6px 0px"</span>,
    <span class="hljs-attr">display</span>: <span class="hljs-string">"flex"</span>,
    <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">"row"</span>,
    <span class="hljs-attr">justifyContent</span>: <span class="hljs-string">"center"</span>,
    <span class="hljs-attr">alignItems</span>: <span class="hljs-string">"center"</span>,
  },
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">color</span>: <span class="hljs-string">"#8661d1"</span>,
    <span class="hljs-attr">fontFamily</span>: <span class="hljs-string">"Poppins"</span>,
    <span class="hljs-attr">fontStyle</span>: <span class="hljs-string">"bold"</span>,
  },
  <span class="hljs-attr">image</span>: {
    <span class="hljs-attr">marginRight</span>: <span class="hljs-string">"25px"</span>,
  },
}));
</code></pre>
<p>Finally, go to App.js and import all of the necessary component files, styles, and components from the core material ui library, then implement it as follows.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//App.js</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { Container, AppBar, Typography, Grow, Grid } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> blogLogo <span class="hljs-keyword">from</span> <span class="hljs-string">"./Assets/blogLogo.gif"</span>;
<span class="hljs-keyword">import</span> BlogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/BlogPosts"</span>;
<span class="hljs-keyword">import</span> BlogPostsForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/BlogPostsForm"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles/app.styles.js"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> appStyles = useStyles();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">maxWidth</span>=<span class="hljs-string">"xl"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AppBar</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.navigationBar}</span>
          <span class="hljs-attr">position</span>=<span class="hljs-string">"static"</span>
          <span class="hljs-attr">color</span>=<span class="hljs-string">"inherit"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.image}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{blogLogo}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"icon"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.title}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h4"</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>&gt;</span>
            Mern awesome blog
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">AppBar</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grow</span> <span class="hljs-attr">in</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Container</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span>
              <span class="hljs-attr">container</span>
              <span class="hljs-attr">justify</span>=<span class="hljs-string">"space-between"</span>
              <span class="hljs-attr">alignItems</span>=<span class="hljs-string">"stretch"</span>
              <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{7}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">BlogPostsForm</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{4}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">BlogPosts</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grow</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now lets finally connect our frontend with the backend . so for that lets create a folder name api and inside it create a file name api.js . So let's import axios to make api calls, then specify our backend server url and write a function that simply fetches the post using axios.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> url = <span class="hljs-string">"http://localhost:4000/api/blogs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchAllBlogPosts = <span class="hljs-function">() =&gt;</span> axios.get(url);
</code></pre>
<p>Now, let's focus on adding redux functionality to our react application because all of our backend actions will be done with redux, so we need to dispatch those actions. To do that, let's create some files and folders to structure it so that our application can be scalable.So, inside our src folder, create a folder called actions as well as a folder called reducers, and inside both of those folders, create a file called blogPosts.js</p>
<p>Your folder structure should resemble something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635928740517-image.png" alt="Folder structure" /></p>
<p>Before we proceed, let's fix our index.js file so that we can begin using redux from within it. Inside that file, let's import provider, which will keep track of the store, which is the global state, and which will allow us to access the store from anywhere within the application so that we don't have to be on the parent or even the child component so that we can easily access that state from anywhere, and after that, let's import createStore, applyMiddleware, and compose from the redux package, and finally, let's import thunk from redux-thunk and let's setup our index.js file accordingly.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//index.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { createStore, applyMiddleware, compose } <span class="hljs-keyword">from</span> <span class="hljs-string">"redux"</span>;
<span class="hljs-keyword">import</span> thunk <span class="hljs-keyword">from</span> <span class="hljs-string">"redux-thunk"</span>;
<span class="hljs-keyword">import</span> { reducers } <span class="hljs-keyword">from</span> <span class="hljs-string">"./reducers/blogPosts.js"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> store = createStore(reducers, compose(applyMiddleware(thunk)));

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)
);
</code></pre>
<p>If you run your application now, you may encounter the module not found error.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635930721146-image-resized.png" alt="Module not found error" /></p>
<p>Let's go to our reducer folder and fix that error, so let's create an index.js file inside it and import combineReducers from the redux package, export and call that combineReducers as a function, and put an object inside of it. Now we can imlement all of the individual reducers that we have in this application case, which is only going to have blogPosts.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// reducers/index.js</span>
<span class="hljs-keyword">import</span> { combineReducers } <span class="hljs-keyword">from</span> <span class="hljs-string">"redux"</span>;
<span class="hljs-keyword">import</span> blogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">"./blogPosts"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> reducers = combineReducers({ blogPosts });
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635932414032-image.png" alt="Folder Structure" /></p>
<p>If everything went well, your application should be running smoothly at this point. We now need to dispatch our action within our main App.js file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">import</span> React, { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { Container, AppBar, Typography, Grow, Grid } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> blogLogo <span class="hljs-keyword">from</span> <span class="hljs-string">"./Assets/blogLogo.gif"</span>;
<span class="hljs-keyword">import</span> Blogs <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Blogs"</span>;
<span class="hljs-keyword">import</span> BlogPostsForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/BlogPostsForm"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles/app.styles.js"</span>;
<span class="hljs-keyword">import</span> { useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { fetchAllBlogPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"./actions/blogPosts"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> dispatch = useDispatch();
  <span class="hljs-keyword">const</span> appStyles = useStyles();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    dispatch(fetchAllBlogPosts());
  }, [dispatch]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">maxWidth</span>=<span class="hljs-string">"xl"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AppBar</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.navigationBar}</span>
          <span class="hljs-attr">position</span>=<span class="hljs-string">"static"</span>
          <span class="hljs-attr">color</span>=<span class="hljs-string">"inherit"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.image}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{blogLogo}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"icon"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.title}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h2"</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>&gt;</span>
            Mern awesome blog
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">AppBar</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grow</span> <span class="hljs-attr">in</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span>
            <span class="hljs-attr">container</span>
            <span class="hljs-attr">justifyContent</span>=<span class="hljs-string">"space-between"</span>
            <span class="hljs-attr">alignItems</span>=<span class="hljs-string">"stretch"</span>
            <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{3}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">BlogPostsForm</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{9}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Blogs</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grow</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, let's go over to our actions and import our api, and then create some Action creators, which are simply functions that return actions, so let's actually implement redux to pass or dispatch the function from data from our backend .</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// actions/blogPosts.js</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> api <span class="hljs-keyword">from</span> <span class="hljs-string">"../api/api.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchAllBlogPosts = <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> api.fetchAllBlogPosts();

    dispatch({ <span class="hljs-attr">type</span>: GET_ALL_BLOGS, <span class="hljs-attr">payload</span>: data });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error.message);
  }
};
</code></pre>
<p>Finally, let us return to our reducers and handle the logic of getting and fetching all of the blog posts.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// reducers/blogPosts.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (posts = [], action) =&gt; {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"GET_ALL_BLOGS"</span>:
      <span class="hljs-keyword">return</span> action.payload;
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> posts;
  }
};
</code></pre>
<p>Now, let's actually retrieve these data from our child components, so let's go to our Blogs component and fetch the data from the global redux store we can do that by the help of useSelector</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//components/Blogs</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Grid, CircularProgress } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> { useSelector } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;

<span class="hljs-keyword">import</span> BlogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">"../BlogPosts"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles"</span>;

<span class="hljs-keyword">const</span> Blogs = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> posts = useSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.blogPosts);
  <span class="hljs-keyword">const</span> classes = useStyles();

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"this is post"</span>, posts);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BlogPosts</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Blogs;
</code></pre>
<p>When you run your app, you may see an empty array and a network error; to fix this, simply include a proxy in your package.json file</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635934997210-image-resized.png" alt="proxy" /></p>
<p>So, if you still see that empty array, it means that the data was successfully fetched, and it is now time to implement the form so that we can make a post request to our database and actually add new posts to it.</p>
<p>So for that lets head over to the BlogPostsForm component and create a form. First step lets import all the component from material ui core library that we are going to implement in our form</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BlogPostsForm.js</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Paper, TextField, Typography, Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> { useDispatch, useSelector } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> FileBase <span class="hljs-keyword">from</span> <span class="hljs-string">"react-file-base64"</span>;

<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles"</span>;
<span class="hljs-keyword">import</span> { addBlogPosts, editBlogPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../actions/blogPosts"</span>;

<span class="hljs-keyword">const</span> BlogPostsForm = <span class="hljs-function">(<span class="hljs-params">{ blogPostId, setBlogPostId }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [blogInfo, setBlogInfo] = useState({
    <span class="hljs-attr">creator</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">tags</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">fileUpload</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> post = useSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span>
    blogPostId
      ? state.posts.find(<span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> message._id === blogPostId)
      : <span class="hljs-literal">null</span>
  );
  <span class="hljs-keyword">const</span> dispatch = useDispatch();
  <span class="hljs-keyword">const</span> blogPostsStyles = useStyles();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (post) setBlogInfo(post);
  }, [post]);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();

    <span class="hljs-keyword">if</span> (blogPostId === <span class="hljs-number">0</span>) {
      dispatch(addBlogPosts(blogInfo));
    } <span class="hljs-keyword">else</span> {
      dispatch(editBlogPosts(blogInfo));
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Paper</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostsStyles.paper}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span>
        <span class="hljs-attr">autoComplete</span>=<span class="hljs-string">"on"</span>
        <span class="hljs-attr">noValidate</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">blogPostsStyles.root</span>} ${<span class="hljs-attr">blogPostsStyles.form</span>}`}
        <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h5"</span>&gt;</span>
          {blogPostId ? `Update "${post.title}"` : "✨ Create a blog ✨"}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostsStyles.chooseFile}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span>&gt;</span> 🖼️ Upload Blog Image<span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FileBase</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span>
            <span class="hljs-attr">multiple</span>=<span class="hljs-string">{false}</span>
            <span class="hljs-attr">onDone</span>=<span class="hljs-string">{({</span> <span class="hljs-attr">base64</span> }) =&gt;</span>
              setBlogInfo({ ...blogInfo, fileUpload: base64 })
            }
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
          <span class="hljs-attr">label</span>=<span class="hljs-string">"🔥 Blog Title"</span>
          <span class="hljs-attr">fullWidth</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{blogInfo.title}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setBlogInfo({ ...blogInfo, title: e.target.value })}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
          <span class="hljs-attr">label</span>=<span class="hljs-string">"📙 Blog Description"</span>
          <span class="hljs-attr">fullWidth</span>
          <span class="hljs-attr">multiline</span>
          <span class="hljs-attr">rows</span>=<span class="hljs-string">{7}</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{blogInfo.description}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
            setBlogInfo({ ...blogInfo, description: e.target.value })
          }
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"creator"</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
          <span class="hljs-attr">label</span>=<span class="hljs-string">"✍️ Author name"</span>
          <span class="hljs-attr">fullWidth</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{blogInfo.creator}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
            setBlogInfo({ ...blogInfo, creator: e.target.value })
          }
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span>&gt;</span>Tags (5 max seperated by comma)<span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"tags"</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
          <span class="hljs-attr">label</span>=<span class="hljs-string">"🏷️ Tags"</span>
          <span class="hljs-attr">fullWidth</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{blogInfo.tags}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
            setBlogInfo({ ...blogInfo, tags: e.target.value.split(",") })
          }
        /&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostsStyles.publishButton}</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span>
          <span class="hljs-attr">color</span>=<span class="hljs-string">"secondary"</span>
          <span class="hljs-attr">size</span>=<span class="hljs-string">"large"</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
        &gt;</span>
          Publish 📝
        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Paper</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> BlogPostsForm;
</code></pre>
<p>Also, don't forget to modify the blogPostForm styles within styles. js</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/BlogPostsForm/styles.js</span>
<span class="hljs-keyword">import</span> { makeStyles } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core/styles"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> makeStyles(<span class="hljs-function">(<span class="hljs-params">theme</span>) =&gt;</span> ({
  <span class="hljs-attr">root</span>: {
    <span class="hljs-string">"&amp; .MuiTextField-root"</span>: {
      <span class="hljs-attr">margin</span>: theme.spacing(<span class="hljs-number">1</span>),
    },
  },
  <span class="hljs-attr">paper</span>: {
    <span class="hljs-attr">padding</span>: theme.spacing(<span class="hljs-number">5</span>),
  },
  <span class="hljs-attr">chooseFile</span>: {
    <span class="hljs-attr">width</span>: <span class="hljs-string">"95%"</span>,
    <span class="hljs-attr">margin</span>: <span class="hljs-string">"10px 0"</span>,
  },
  <span class="hljs-attr">publishButton</span>: {
    <span class="hljs-attr">marginBottom</span>: <span class="hljs-number">10</span>,
  },
  <span class="hljs-attr">form</span>: {
    <span class="hljs-attr">display</span>: <span class="hljs-string">"flex"</span>,
    <span class="hljs-attr">flexWrap</span>: <span class="hljs-string">"wrap"</span>,
    <span class="hljs-attr">justifyContent</span>: <span class="hljs-string">"center"</span>,
  },
}));
</code></pre>
<p>So before going any further lets fix our api first</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// api/api.js</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> url = <span class="hljs-string">"http://localhost:4000/api/blogs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchBlogPosts = <span class="hljs-function">() =&gt;</span> axios.get(url);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addNewBlogPost = <span class="hljs-function">(<span class="hljs-params">newBlog</span>) =&gt;</span> axios.post(url, newBlog);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editSingleBlogPost = <span class="hljs-function">(<span class="hljs-params">id, editedBlogPost</span>) =&gt;</span>
  axios.patch(<span class="hljs-string">`<span class="hljs-subst">${url}</span>/<span class="hljs-subst">${id}</span>`</span>, editedBlogPost);
</code></pre>
<p>After you've successfully added and exported the addNewBlogPost and editSingleBlogPost functions, let's actually implement them by creating some actions called addBlogPosts and editBlogPosts, respectively.</p>
<p><strong><em>addBlogPosts action</em></strong>
<img src="https://aviyel.com/assets/uploads/files/1636000217533-image-resized.png" alt="add blog post" /></p>
<p><strong><em>editBlogPosts action</em></strong>
<img src="https://aviyel.com/assets/uploads/files/1636000237947-image-resized.png" alt="edit blog post" /></p>
<p>Your blogPosts.js actions should look something like this.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// actions/blogPosts.js</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> api <span class="hljs-keyword">from</span> <span class="hljs-string">"../api/api.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchAllBlogPosts = <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> api.fetchBlogPosts();

    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"GET_ALL_BLOG_POST"</span>, <span class="hljs-attr">payload</span>: data });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error.message);
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addBlogPosts = <span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> api.addNewBlogPost(post);

    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"ADD_NEW_BLOG_POST"</span>, <span class="hljs-attr">payload</span>: data });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error.message);
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editBlogPosts = <span class="hljs-function">(<span class="hljs-params">id, post</span>) =&gt;</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> api.editSingleBlogPost(id, post);

    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"EDIT_SINGLE_BLOG_POST"</span>, <span class="hljs-attr">payload</span>: data });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error.message);
  }
};
</code></pre>
<p>After that, let's update the reducers section.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (posts = [], action) =&gt; {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">"GET_ALL_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> action.payload;
        <span class="hljs-keyword">case</span> <span class="hljs-string">"ADD_NEW_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> [...posts, action.payload];
        <span class="hljs-keyword">case</span> <span class="hljs-string">"EDIT_SINGLE_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> posts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span>
                post._id === action.payload._id ? action.payload : post
            );
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> posts;
    }
};
</code></pre>
<p>Finally, let's update our App.js to include the blogPostId state, which we'll pass as a prop to our BlogPostsForm and Blogs components.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//App.js</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> { Container, AppBar, Typography, Grow, Grid } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> blogLogo <span class="hljs-keyword">from</span> <span class="hljs-string">"./Assets/blogLogo.gif"</span>;
<span class="hljs-keyword">import</span> Blogs <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Blogs"</span>;
<span class="hljs-keyword">import</span> BlogPostsForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/BlogPostsForm"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles/app.styles.js"</span>;
<span class="hljs-keyword">import</span> { useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> { fetchAllBlogPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"./actions/blogPosts"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [blogPostId, setBlogPostId] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> dispatch = useDispatch();
  <span class="hljs-keyword">const</span> appStyles = useStyles();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    dispatch(fetchAllBlogPosts());
  }, [blogPostId, dispatch]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Container</span> <span class="hljs-attr">maxWidth</span>=<span class="hljs-string">"xl"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AppBar</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.navigationBar}</span>
          <span class="hljs-attr">position</span>=<span class="hljs-string">"static"</span>
          <span class="hljs-attr">color</span>=<span class="hljs-string">"inherit"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.image}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{blogLogo}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"icon"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{appStyles.title}</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h2"</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>&gt;</span>
            Mern awesome blog
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">AppBar</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Grow</span> <span class="hljs-attr">in</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span>
            <span class="hljs-attr">container</span>
            <span class="hljs-attr">justifyContent</span>=<span class="hljs-string">"space-between"</span>
            <span class="hljs-attr">alignItems</span>=<span class="hljs-string">"stretch"</span>
            <span class="hljs-attr">spacing</span>=<span class="hljs-string">{2}</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{3}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">BlogPostsForm</span>
                <span class="hljs-attr">blogPostId</span>=<span class="hljs-string">{blogPostId}</span>
                <span class="hljs-attr">setBlogPostId</span>=<span class="hljs-string">{setBlogPostId}</span>
              /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{9}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Blogs</span> <span class="hljs-attr">setBlogPostId</span>=<span class="hljs-string">{setBlogPostId}</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grow</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>After we've fixed App.js, we'll move on to our Blogs component and use the passed props within it and also drill it to the BlogPosts components</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Blogs.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Grid, CircularProgress } <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core"</span>;
<span class="hljs-keyword">import</span> { useSelector } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;

<span class="hljs-keyword">import</span> BlogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">"../BlogPosts"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles"</span>;

<span class="hljs-keyword">const</span> Blogs = <span class="hljs-function">(<span class="hljs-params">{ setBlogPostId }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> posts = useSelector(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.posts);
  <span class="hljs-keyword">const</span> classes = useStyles();

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"this is post"</span>, posts);

  <span class="hljs-keyword">return</span> !posts.length ? (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">CircularProgress</span> /&gt;</span></span>
  ) : (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Grid</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.container}</span>
      <span class="hljs-attr">container</span>
      <span class="hljs-attr">alignItems</span>=<span class="hljs-string">"stretch"</span>
      <span class="hljs-attr">spacing</span>=<span class="hljs-string">{4}</span>
    &gt;</span>
      {posts.map((post) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Grid</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post._id}</span> <span class="hljs-attr">item</span> <span class="hljs-attr">xs</span>=<span class="hljs-string">{12}</span> <span class="hljs-attr">sm</span>=<span class="hljs-string">{12}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">BlogPosts</span> <span class="hljs-attr">post</span>=<span class="hljs-string">{post}</span> <span class="hljs-attr">setBlogPostId</span>=<span class="hljs-string">{setBlogPostId}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Grid</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Blogs;
</code></pre>
<p>Now that we've completed almost everything, it's time to work on the individual blog posts. To do so, go to the BlogPosts components and install material UI icons first, then import several components from the material UI core library, and finally copy and paste the following code inside it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/BlogPosts.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> {
  Typography,
  CardMedia,
  Button,
  Card,
  CardActions,
  CardContent,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/core/"</span>;
<span class="hljs-keyword">import</span> ArrowUpwardIcon <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/icons/ArrowUpward"</span>;
<span class="hljs-keyword">import</span> DeleteIcon <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/icons/Delete"</span>;
<span class="hljs-keyword">import</span> EditIcon <span class="hljs-keyword">from</span> <span class="hljs-string">"@material-ui/icons/Edit"</span>;
<span class="hljs-keyword">import</span> moment <span class="hljs-keyword">from</span> <span class="hljs-string">"moment"</span>;
<span class="hljs-keyword">import</span> { useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;
<span class="hljs-keyword">import</span> blogImageLogo <span class="hljs-keyword">from</span> <span class="hljs-string">"../../Assets/blogLogo.gif"</span>;

<span class="hljs-keyword">import</span> { upvoteBlogPosts, removeBlogPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../actions/blogPosts"</span>;
<span class="hljs-keyword">import</span> useStyles <span class="hljs-keyword">from</span> <span class="hljs-string">"./styles"</span>;

<span class="hljs-keyword">const</span> BlogPosts = <span class="hljs-function">(<span class="hljs-params">{ post, setCurrentId }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> dispatch = useDispatch();
  <span class="hljs-keyword">const</span> blogPostStyles = useStyles();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.blogContainer}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">CardMedia</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.imageContainer}</span>
          <span class="hljs-attr">image</span>=<span class="hljs-string">{post.fileUpload</span> || <span class="hljs-attr">blogImageLogo</span>}
          <span class="hljs-attr">title</span>=<span class="hljs-string">{post.title}</span>
        /&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.nameOverlay}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"h6"</span>&gt;</span> {post.creator} <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>{" "}
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span>&gt;</span>
            {" "}
            {moment(post.createdAt).fromNow()}{" "}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.editOverlay}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
              <span class="hljs-attr">color:</span> "<span class="hljs-attr">white</span>",
            }}
            <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setCurrentId(post._id)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">EditIcon</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"default"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.tagSection}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"textSecondary"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"h2"</span>&gt;</span>
            {" "}
            {post.tags.map((tag) =&gt; `#${tag} `)}{" "}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.titleSection}</span>
          <span class="hljs-attr">gutterBottom</span>
          <span class="hljs-attr">variant</span>=<span class="hljs-string">"h5"</span>
          <span class="hljs-attr">component</span>=<span class="hljs-string">"h2"</span>
        &gt;</span>
          {post.title}{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">CardContent</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Typography</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"body2"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"textSecondary"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"p"</span>&gt;</span>
            {" "}
            {post.description}{" "}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Typography</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">CardContent</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;<span class="hljs-name">CardActions</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{blogPostStyles.cardActions}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
            <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span>
            <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> dispatch(upvoteBlogPosts(post._id))}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ArrowUpwardIcon</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"small"</span> /&gt;</span> {post.likeCount}{" "}
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>{" "}
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
            <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span>
            <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> dispatch(removeBlogPosts(post._id))}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">DeleteIcon</span> <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"big"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>{" "}
        <span class="hljs-tag">&lt;/<span class="hljs-name">CardActions</span>&gt;</span>{" "}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Card</span>&gt;</span>{" "}
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> BlogPosts;
</code></pre>
<p>Finally, let's create an action to actually upvote and remove the blog post. First, create a function inside API and name it upvoteSingleBlogPost and removeBlogPost, then export it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// api/api.js</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> url = <span class="hljs-string">"http://localhost:4000/api/blogs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchBlogPosts = <span class="hljs-function">() =&gt;</span> axios.get(url);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addNewBlogPost = <span class="hljs-function">(<span class="hljs-params">newBlog</span>) =&gt;</span> axios.post(url, newBlog);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editSingleBlogPost = <span class="hljs-function">(<span class="hljs-params">id, editedBlogPost</span>) =&gt;</span>
    axios.patch(<span class="hljs-string">`<span class="hljs-subst">${url}</span>/<span class="hljs-subst">${id}</span>`</span>, editedBlogPost);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> upvoteSingleBlogPost = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span>
    axios.patch(<span class="hljs-string">`<span class="hljs-subst">${url}</span>/<span class="hljs-subst">${id}</span>/likedBlogPost`</span>);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> removeBlogPost = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> axios.delete(<span class="hljs-string">`<span class="hljs-subst">${url}</span>/<span class="hljs-subst">${id}</span>`</span>);
</code></pre>
<p>Finally, let us fix our reducers and we will be finished with our application.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// reducers/blogPosts.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (posts = [], action) =&gt; {
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">"GET_ALL_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> action.payload;
        <span class="hljs-keyword">case</span> <span class="hljs-string">"ADD_NEW_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> [...posts, action.payload];
        <span class="hljs-keyword">case</span> <span class="hljs-string">"EDIT_SINGLE_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> posts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span>
                post._id === action.payload._id ? action.payload : post
            );
        <span class="hljs-keyword">case</span> <span class="hljs-string">"UPVOTE_SINGLE_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> posts.map(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span>
                post._id === action.payload._id ? action.payload : post
            );
        <span class="hljs-keyword">case</span> <span class="hljs-string">"DELETE_SINGLE_BLOG_POST"</span>:
            <span class="hljs-keyword">return</span> posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> post._id !== action.payload);
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> posts;
    }
};
</code></pre>
<p>We've gone over quite a lot of material to give you the knowledge you need to build a fully-fledged MERN stack application from absolute scratch.</p>
<p>The complete source code can be found here.</p>
<p><a target="_blank" href="https://github.com/pramit-marattha/MERN-awesome-blog">https://github.com/pramit-marattha/MERN-awesome-blog</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the first section of this blog tutorial, we built the back-end server using Node.js, Express, and MongoDB. We used the Mongoose library to connect the Node.js / Express server to MongoDB, and then in the second section of this tutorial, we created the React front-end application and also used redux for managing our states globally for our MERN stack blog application. Cheers !! Happy Coding !!</p>
<p>Main article available here =&gt; https://aviyel.com/post/1304</p>
<p>Happy Coding!! </p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Join Aviyel's Discord =&gt; <a target="_blank" href="https://discord.gg/TbfZmbvnN5">Aviyel's world</a></p>
<p>Twitter =&gt;[https://twitter.com/AviyelHq]</p>
]]></content:encoded></item><item><title><![CDATA[Crafting a stunning CRUD application with MERN stack   🔥]]></title><description><![CDATA[In this blog tutorial, we will set up a full-stack app to perform CRUD operations using the MERN stack, MongoDB for the database, Express and Node for the backend, and React as the frontend. This blog tutorial should help you understand the basic MER...]]></description><link>https://pramitmarattha.com.np/crafting-a-stunning-crud-application-with-mern-stack</link><guid isPermaLink="true">https://pramitmarattha.com.np/crafting-a-stunning-crud-application-with-mern-stack</guid><category><![CDATA[Node.js]]></category><category><![CDATA[React]]></category><category><![CDATA[MERN Stack]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Mon, 29 Nov 2021 13:17:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638191755586/eJDHqvVRy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog tutorial, we will set up a full-stack app to perform CRUD operations using the MERN stack, MongoDB for the database, Express and Node for the backend, and React as the frontend. This blog tutorial should help you understand the basic MERN stack CRUD operations.</p>
<p>Here's a look at the final version of our application.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635343378933-image-resized.png" alt="Demo" /></p>
<h2 id="heading-setting-up-frontend">Setting up Frontend</h2>
<p>We'll start by setting up our frontend first using create-react-app  . So, without further ado, let's get started.</p>
<p>Create a two folder name client and server inside your project directory, then open it in Visual Studio Code or any code editor of your choice.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635317522020-image.png" alt="Client Directory" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635317487142-image.png" alt="Server Directory" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635316363482-image.png" alt="Folder Structure" /></p>
<p>We will be building the UI and its functionalities from absolute ground level. Now, lets start and craft our application.</p>
<p>Installing react application</p>
<p>Let us begin with the frontend part and craft it using react. So, if Node.js isn't already installed on your system, the first thing you should do is install it. So, go to the official Node.js website and install the correct and appropriate version. We need node js so that we can use the node package manager, also known as NPM.</p>
<p>Now, open client folder inside the code editor of your choice. For this tutorial, I will be using VScode. Next step, let’s open the integrated terminal and type npx create-react-app . this command will create the app inside the current directory and that application will be named as client</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635330282631-image-resized.png" alt="npx" /></p>
<p>It usually takes only a few minutes to install. Normally, we would use npm to download packages into the project, but in this case, we are using npx, the package runner, which will download and configure everything for us so that we can start with an amazing template. It's now time to start our development server, so simply type npm start, and the browser will automatically open react-app.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635330419245-image-resized.png" alt="Starting react app" /></p>
<p>Now, within the client folder install the following dependencies.</p>
<pre><code class="lang-javascript">npm i axios react-router-dom
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635343285644-image-resized.png" alt="Dependencies" /></p>
<p>The  "package.json" file should look like this after the dependencies have been installed.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"client"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"@testing-library/jest-dom"</span>: <span class="hljs-string">"^5.14.1"</span>,
    <span class="hljs-attr">"@testing-library/react"</span>: <span class="hljs-string">"^11.2.7"</span>,
    <span class="hljs-attr">"@testing-library/user-event"</span>: <span class="hljs-string">"^12.8.3"</span>,
    <span class="hljs-attr">"axios"</span>: <span class="hljs-string">"^0.24.0"</span>,
    <span class="hljs-attr">"react"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-dom"</span>: <span class="hljs-string">"^17.0.2"</span>,
    <span class="hljs-attr">"react-router-dom"</span>: <span class="hljs-string">"^5.3.0"</span>,
    <span class="hljs-attr">"react-scripts"</span>: <span class="hljs-string">"4.0.3"</span>,
    <span class="hljs-attr">"web-vitals"</span>: <span class="hljs-string">"^1.1.2"</span>
  },
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"react-scripts start"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"react-scripts build"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"react-scripts test"</span>,
    <span class="hljs-attr">"eject"</span>: <span class="hljs-string">"react-scripts eject"</span>
  },
  <span class="hljs-attr">"eslintConfig"</span>: {
    <span class="hljs-attr">"extends"</span>: [
      <span class="hljs-string">"react-app"</span>,
      <span class="hljs-string">"react-app/jest"</span>
    ]
  },
  <span class="hljs-attr">"browserslist"</span>: {
    <span class="hljs-attr">"production"</span>: [
      <span class="hljs-string">"&gt;0.2%"</span>,
      <span class="hljs-string">"not dead"</span>,
      <span class="hljs-string">"not op_mini all"</span>
    ],
    <span class="hljs-attr">"development"</span>: [
      <span class="hljs-string">"last 1 chrome version"</span>,
      <span class="hljs-string">"last 1 firefox version"</span>,
      <span class="hljs-string">"last 1 safari version"</span>
    ]
  }
}
</code></pre>
<h2 id="heading-project-cleanup">Project cleanup</h2>
<p>Before we begin building our projects, we must first clean them up by removing some of the files provided by create-react-app. Your src files should look like this after you've cleaned them up</p>
<p><img src="https://aviyel.com/assets/uploads/files/1634550649379-image.png" alt="Folder structure" /></p>
<p>Now, within the src folder, make another folder called components, and within that folder, make three folder/components: DisplayTodo, CreateTodo, TodoLists and UpdateTodo.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635337628345-image.png" alt="Components" /></p>
<p><strong><em>DisplayTodo</em></strong>
<img src="https://aviyel.com/assets/uploads/files/1635394378729-image.png" alt="Display Todo" /></p>
<p>To begin, we will create the DisplayTodo component, which will read all of the documents created. The first step is, import the react useState and useEffect hooks and then import axios from the Axios package. We will retrieve documents from the database and store them in the state todoData in the DisplayTodo  function component. To retrieve the document, we will use axios to send a GET request to the backend. When we receive the data, we will use setTodoData to store it in todoData and log it. If we receive an error, we will also log it. Because we want the data to load when the page loads, we'll make the GET request from the useEffect hook.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/DisplayTodo.js</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> TodoLists <span class="hljs-keyword">from</span> <span class="hljs-string">"../TodoLists"</span>;

<span class="hljs-keyword">const</span> DisplayTodo = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [infoTodo, setInfoTodo] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    axios
      .get(<span class="hljs-string">"http://localhost:4000/api/todoapp"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(res.data);
        setInfoTodo(res.data);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(err);
      });
  }, []);

  <span class="hljs-keyword">const</span> deleteHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    axios.delete(<span class="hljs-string">`http://localhost:4000/api/todoapp/<span class="hljs-subst">${e.target.name}</span>`</span>);
    setInfoTodo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo._id !== e.target.name);
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/add-todo"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn-new"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>Add new todo<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list-block"</span>&gt;</span>
          {infoTodo.map((data) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">TodoCard</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{data}</span> <span class="hljs-attr">deleteHandler</span>=<span class="hljs-string">{deleteHandler}</span> /&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DisplayTodo;
</code></pre>
<p><strong><em>TodoList</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394457438-image.png" alt="TodoList component" /></p>
<p>Then we'll make the TodoList component to display the todo's contents. We will iterate over todoData and pass the contents to TodoList , which will display the contents of each to-do document.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/TodoList.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> TodoList = <span class="hljs-function">(<span class="hljs-params">{ todoInfos, deleteHandler }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { _id, tilte, description } = todoInfos;
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{_id}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title-description"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span>&gt;</span>
          🖊️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{deleteHandler}</span>&gt;</span>
          🗑️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};
</code></pre>
<p><strong><em>CreateTodo</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394507727-image.png" alt="Create Todo" /></p>
<p>To create a new todo, we will use axios to send a POST request to our server. So let’s import the react useState hook and after that, import the Link from react-router-dom.</p>
<p>Now, create a function handler change that and you'll get the input data again create a new function handler. Finally, Submitting this will cause the POST request to be sent to the server. Declare data using the useState hook and the JSON below.</p>
<pre><code><span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"title"</span>: <span class="hljs-string">""</span>
</code></pre><p>When the input changes, we will update the data in the handleChange method. We'll call setTodoInfo() and declare an arrow function inside that will copy the previous data's contents if any exist. In this case, e.target.name will be the name of the input element, which will either have a title or a description. In the submitHanlder method, To prevent the page from reloading when the submit button is clicked, use e.preventDefault() Send the data in the form of a POST request to the server. If the data was successfully transmitted to the server, the state data should be reset.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/CreateTodo.js</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> CreateTodo = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [todoInfo, setTodoInfo] = useState({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleChange</span>(<span class="hljs-params">e</span>) </span>{
    setTodoInfo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> ({ ...data, [e.target.name]: e.target.value }));
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSubmit</span>(<span class="hljs-params">e</span>) </span>{
    e.preventDefault();

    axios
      .post(<span class="hljs-string">"http://localhost:4000/api/todoapp"</span>, todoInfo)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        setTodoInfo({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });
        <span class="hljs-built_in">console</span>.log(res.data.message);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error couldn't create TODO"</span>);
        <span class="hljs-built_in">console</span>.log(err.message);
      });
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn todo-btn-back"</span>&gt;</span>
        🔙 back
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-container"</span> <span class="hljs-attr">noValidate</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span>&gt;</span>
            Todo Title
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{todoInfo.title}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span>&gt;</span>
            Describe it !
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"textarea"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{todoInfo.description}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>
            ➕ create todo
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CreateTodo;
</code></pre>
<p>Now, let’s define a deleteHandler function inside DisplayTodo component that will send a DELETE request to the server. To delete a document from the database, this function will require the document's _id. It will also add the filtered array to the array todo. TodoList component accepts the deleteHandler  method as a parameter. TodoList  component should be updated to include the deleteHandler parameter. Add a onClick event for the delete button and pass the deleteHandler method as a parameter.
After making the aforementioned changes, the code will look something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394378729-image.png" alt="Display Todo component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//components/DisplayTodo.js</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> TodoLists <span class="hljs-keyword">from</span> <span class="hljs-string">"../TodoLists"</span>;

<span class="hljs-keyword">const</span> DisplayTodo = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [infoTodo, setInfoTodo] = useState([]);
  <span class="hljs-keyword">const</span> [id, setId] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [infoTodo, setInfoTodo] = useState([]);
  <span class="hljs-keyword">const</span> [modal, setModal] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    axios
      .get(<span class="hljs-string">"http://localhost:8000/api/todo"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(res.data);
        setInfoTodo(res.data);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(err);
      });
  }, []);

  <span class="hljs-keyword">const</span> updateHandler = <span class="hljs-function">() =&gt;</span> {
    setUpdate(!update);
  };

  <span class="hljs-keyword">const</span> closeHandler = <span class="hljs-function">() =&gt;</span> {
    setId(<span class="hljs-string">""</span>);
    setModal(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">const</span> deleteHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    axios.delete(<span class="hljs-string">`http://localhost:8000/api/todo/<span class="hljs-subst">${e.target.name}</span>`</span>);
    setInfoTodo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo._id !== e.target.name);
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>➕ Add new todo<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list-block"</span>&gt;</span>
          {infoTodo.map((todoInfo, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">TodoLists</span>
              <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
              <span class="hljs-attr">todoInfos</span>=<span class="hljs-string">{todoInfo}</span>
              <span class="hljs-attr">deleteHandler</span>=<span class="hljs-string">{deleteHandler}</span>
            /&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      {modal ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-todo-data"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close"</span>&gt;</span>
              <span class="hljs-symbol">&amp;times;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      ) : (
        ""
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DisplayTodo;
</code></pre>
<p>TodoList component should look something like this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394457438-image.png" alt="TodoList" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/TodoList.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> TodoLists = <span class="hljs-function">(<span class="hljs-params">{ todoInfos }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { _id, title, description } = todoInfos;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{_id}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title-description"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span>&gt;</span>
          🖊️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span>&gt;</span>
          🗑️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TodoLists;\
</code></pre>
<p>We must first update the App.js file before we can use the CreateTodo component. BrowserRouter and Route should be imported from react-router-dom. Import the CreateTodo component from the components/createTodo directory. Create a Route for the home page and pass the ShowTodoList component through it and make a Route for adding a new todo /add-list and wrap the Routes within the BrowserRouter.</p>
<p>After you've made the changes, the App.js file should look like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394636966-image.png" alt="App component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>

<span class="hljs-keyword">import</span> { BrowserRouter, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> DisplayTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/DisplayTodo"</span>;
<span class="hljs-keyword">import</span> CreateTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/CreateTodo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-Container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{DisplayTodo}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/add-list"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{CreateTodo}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, import the Link from react-router-dom. and wrap a button within a Link tag. After you've made the changes, the DisplayTodo should look like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394378729-image.png" alt="Display Todo Component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/DisplayTodo.js</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> TodoLists <span class="hljs-keyword">from</span> <span class="hljs-string">"../TodoLists"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DisplayTodo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [id, setId] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [infoTodo, setInfoTodo] = useState([]);
  <span class="hljs-keyword">const</span> [modal, setModal] = useState(<span class="hljs-literal">false</span>);

  useEffect(
    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      axios
        .get(<span class="hljs-string">"http://localhost:4000/api/todoapp"</span>)
        .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
          setInfoTodo(res.data);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(err.message);
        });
    },
    [update]
  );

  <span class="hljs-keyword">const</span> editHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setId(e.target.name);
    setModal(<span class="hljs-literal">true</span>);
  };

  <span class="hljs-keyword">const</span> updateHandler = <span class="hljs-function">() =&gt;</span> {
    setUpdate(!update);
  };

  <span class="hljs-keyword">const</span> deleteHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    axios.delete(<span class="hljs-string">`http://localhost:4000/api/todoapp/<span class="hljs-subst">${e.target.name}</span>`</span>);

    setInfoTodo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo._id !== e.target.name);
    });
  };

  <span class="hljs-keyword">const</span> closeHandler = <span class="hljs-function">() =&gt;</span> {
    setId(<span class="hljs-string">""</span>);
    setModal(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/add-list"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button-new"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>➕ Add new todo<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list-block"</span>&gt;</span>
          {infoTodo.map((todoInfo, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">TodoLists</span>
              <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
              <span class="hljs-attr">todoInfos</span>=<span class="hljs-string">{todoInfo}</span>
              <span class="hljs-attr">editHandler</span>=<span class="hljs-string">{editHandler}</span>
              <span class="hljs-attr">deleteHandler</span>=<span class="hljs-string">{deleteHandler}</span>
            /&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      {modal ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-todo-data"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close"</span>&gt;</span>
              <span class="hljs-symbol">&amp;times;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      ) : (
        ""
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DisplayTodo;
</code></pre>
<p>Now again, import the Link from react-router-dom and wrap a button within a Link tag. After you've made the changes, the CreateTodo should look like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394507727-image.png" alt="Create Todo Component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/CreateTodo.js</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> CreateTodo = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [todoInfo, setTodoInfo] = useState({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleChange</span>(<span class="hljs-params">e</span>) </span>{
    setTodoInfo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> ({ ...data, [e.target.name]: e.target.value }));
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSubmit</span>(<span class="hljs-params">e</span>) </span>{
    e.preventDefault();

    axios
      .post(<span class="hljs-string">"http://localhost:4000/api/todoapp"</span>, todoInfo)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        setTodoInfo({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });
        <span class="hljs-built_in">console</span>.log(res.data.message);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error couldn't create TODO"</span>);
        <span class="hljs-built_in">console</span>.log(err.message);
      });
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn todo-btn-back"</span>&gt;</span>
          🔙 back
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-container"</span> <span class="hljs-attr">noValidate</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span>&gt;</span>
            Todo Title
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{todoInfo.title}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span>&gt;</span>
            Describe it !
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"textarea"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{todoInfo.description}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>
            ➕ create todo
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CreateTodo;
</code></pre>
<p>Now, import the useState from react and import axios from the axios package. Finally, The UpdateTodo component will have three properties._id ,closeHandler , updateHandler 
The UpdateTodo component may look something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394754478-image.png" alt="Update Todo Component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//components/UpdateTodo.js</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateTodo</span>(<span class="hljs-params">{ _id, closeHandler, updateHandler }</span>) </span>{
  <span class="hljs-keyword">const</span> [todoInfo, setTodoInfo] = useState({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setTodoInfo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> ({ ...data, [e.target.name]: e.target.value }));
  };

  <span class="hljs-keyword">const</span> submitHanlder = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    axios
      .put(<span class="hljs-string">`http://localhost:4000/api/todoapp/<span class="hljs-subst">${_id}</span>`</span>, todoInfo)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        setTodoInfo({ <span class="hljs-attr">title</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">description</span>: <span class="hljs-string">""</span> });
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(err);
      });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"form-container"</span>
      <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
        submitHanlder(e);
        updateHandler();
        closeHandler();
      }}
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span>&gt;</span>
        Todo Title
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span>&gt;</span>
        Todo Description
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"textarea"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>
        ➕ Add
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UpdateTodo;
</code></pre>
<p>Import the UpdateTodo component from UpdateTodo.js and then declare modal with the useState hook which is set to false by default. The modal value will be either true or false. The UpdateTodo component will be rendered conditionally if the edit button is pressed on any of the todo, we will set setModal to true when the UpdateTodo component is rendered, and then declare id using the useState hook. The _id of the todo  that needs to be updated will be saved.It will be passed to the UpdateTodo component as a prop. Use the useState hook to declare an update. This will be used to retrieve all of the to-do items from the database. When a todo document is updated, the update will toggle between true and false.Now, define a function editHandler this function will replace the state id with the document's _id and set the modal state to true. Next, create a function called updateHandler. If the todo has been updated by the user, this will invert the state of the update. Inverting the state will cause the useEffect hook to update the todo array. Finally, define a function closeHandler, which will be used to close the UpdateTodo component. This will set the id to an empty string and the modal property to false.</p>
<p>After you've made the changes, the DisplayTodo and TodoList should look like this.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//components/DisplayTodo.js</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> UpdateTodo <span class="hljs-keyword">from</span> <span class="hljs-string">"../UpdateTodo"</span>;
<span class="hljs-keyword">import</span> TodoLists <span class="hljs-keyword">from</span> <span class="hljs-string">"../TodoLists"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DisplayTodo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [id, setId] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [infoTodo, setInfoTodo] = useState([]);
  <span class="hljs-keyword">const</span> [modal, setModal] = useState(<span class="hljs-literal">false</span>);

  useEffect(
    <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      axios
        .get(<span class="hljs-string">"http://localhost:4000/api/todoapp"</span>)
        .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
          setInfoTodo(res.data);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(err.message);
        });
    },
    [update]
  );

  <span class="hljs-keyword">const</span> editHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setId(e.target.name);
    setModal(<span class="hljs-literal">true</span>);
  };

  <span class="hljs-keyword">const</span> updateHandler = <span class="hljs-function">() =&gt;</span> {
    setUpdate(!update);
  };

  <span class="hljs-keyword">const</span> deleteHandler = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    axios.delete(<span class="hljs-string">`http://localhost:4000/api/todoapp/<span class="hljs-subst">${e.target.name}</span>`</span>);

    setInfoTodo(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo._id !== e.target.name);
    });
  };

  <span class="hljs-keyword">const</span> closeHandler = <span class="hljs-function">() =&gt;</span> {
    setId(<span class="hljs-string">""</span>);
    setModal(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/add-list"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button-new"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span>&gt;</span>➕ Add new todo<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-data"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-list-block"</span>&gt;</span>
          {infoTodo.map((todoInfo, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">TodoLists</span>
              <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
              <span class="hljs-attr">todoInfos</span>=<span class="hljs-string">{todoInfo}</span>
              <span class="hljs-attr">editHandler</span>=<span class="hljs-string">{editHandler}</span>
              <span class="hljs-attr">deleteHandler</span>=<span class="hljs-string">{deleteHandler}</span>
            /&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      {modal ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"update-todo-data"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{closeHandler}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close"</span>&gt;</span>
              <span class="hljs-symbol">&amp;times;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">UpdateTodo</span>
              <span class="hljs-attr">_id</span>=<span class="hljs-string">{id}</span>
              <span class="hljs-attr">closeHandler</span>=<span class="hljs-string">{closeHandler}</span>
              <span class="hljs-attr">updateHandler</span>=<span class="hljs-string">{updateHandler}</span>
            /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
      ) : (
        ""
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DisplayTodo;
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635394457438-image.png" alt="TodoList Component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//components/TodoList.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> TodoLists = <span class="hljs-function">(<span class="hljs-params">{ todoInfos, editHandler, deleteHandler }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { _id, title, description } = todoInfos;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{_id}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title-description"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{editHandler}</span>&gt;</span>
          🖊️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo-btn"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{_id}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{deleteHandler}</span>&gt;</span>
          🗑️
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TodoLists;
</code></pre>
<p>Finally, let's incorporate some styles into our project. Now, go to your App.css file and update your style, or simply copy and paste the following CSS code.</p>
<p><a target="_blank" href="https://gist.github.com/pramit-marattha/e88d83b66ce7ca9a01e840f486cf9fc8">https://gist.github.com/pramit-marattha/e88d83b66ce7ca9a01e840f486cf9fc8</a></p>
<hr />
<h2 id="heading-setting-up-backend">Setting up Backend</h2>
<p>Now,we'll start by setting up our backend with npm and installing relevant packages, then set up a MongoDB database, then set up a server with Node and Express, then design a database schema to define a Todo, and then set up API routes to create, read, update, and delete documents from the database.</p>
<p>Now go to your server directory and use the command prompt to run the code below.</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p><strong><em>Updating package.json</em></strong></p>
<p>To install the dependencies, use the following instructions in the terminal.</p>
<pre><code class="lang-bash">npm install cors express dotenv mongoose nodemon
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635322128560-image-resized.png" alt="Dependencies" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635317305213-image-resized.png" alt="Dependencies" /></p>
<p>The "package.json" file should look like this after the dependencies have been installed.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"server"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"nodemon main.js"</span>
  },
  <span class="hljs-attr">"keywords"</span>: [],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"cors"</span>: <span class="hljs-string">"^2.8.5"</span>,
    <span class="hljs-attr">"dotenv"</span>: <span class="hljs-string">"^10.0.0"</span>,
    <span class="hljs-attr">"express"</span>: <span class="hljs-string">"^4.17.1"</span>,
    <span class="hljs-attr">"mongoose"</span>: <span class="hljs-string">"^6.0.12"</span>,
    <span class="hljs-attr">"nodemon"</span>: <span class="hljs-string">"^2.0.14"</span>
  }
}
</code></pre>
<p>And also, remember to update the scripts as well.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635317851884-image.png" alt="Updating scripts" /></p>
<h2 id="heading-structuring-the-folder-inside-the-server">Structuring the folder inside the server:</h2>
<ul>
<li><p><strong><em>configurations :</em></strong> Make a file called database.js in the config folder. The necessary code for connecting to the MongoDB database will be contained in this file.</p>
</li>
<li><p><strong><em>controllers :</em></strong> The files in the controllers’ folder will contain the methods for the endpoints to interface with the database.</p>
</li>
<li><p><strong><em>models :</em></strong> The files that specify the MongoDB schema will be found in the model’s folder.</p>
</li>
<li><p><strong><em>routers :</em></strong> The files with the endpoints will be found in the routers folder.</p>
</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1635317066996-image.png" alt="Folder structure" /></p>
<h2 id="heading-configuring-mainjs">Configuring main.js</h2>
<ul>
<li>Import express module.</li>
<li>Use express() to start our app.</li>
<li>Using the app, create a get method for the endpoint http://localhost:4000.</li>
<li>For our server to run, set the PORT to 4000.</li>
<li>Using our app, you may listen to PORT.</li>
</ul>
<pre><code class="lang-main.js">const express = require("express");
const cors = require("cors");

const dotenv = require("dotenv");

dotenv.config();

const app = express();

const PORT = process.env.PORT || 5000;

// listen
app.listen(PORT, () =&gt;
    console.log(`Server is running on http://localhost:${PORT}`)
);
</code></pre>
<p>Now open your .env file, or create one if you don't have one, and paste the following code inside it.</p>
<pre><code><span class="hljs-attr">PORT</span>=<span class="hljs-number">4000</span>
</code></pre><p>Now use the following code to start the server with nodemon. Ensure that the following command is executed from the project directory.</p>
<pre><code>npm <span class="hljs-keyword">start</span>
</code></pre><p>If the server has started successfully, the terminal should display the following message.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635318350969-image.png" alt="npm start" /></p>
<h2 id="heading-getting-started-with-mongodb">Getting started with MongoDB</h2>
<p><strong><em>So, what is MongoDB?</em></strong></p>
<p>MongoDB is an open source, cross-platform document-oriented database program. MongoDB is a NoSQL database that uses JSON-like documents and optional schemas to store data. MongoDB is a database developed by MongoDB Inc. and published under the terms of the Server Side Public License.</p>
<p><strong><em>Sign in to MongoDB</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635322431066-image-resized.png" alt="Sign in MongoDB" /></p>
<p><strong><em>Make a new project.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635322398021-image-resized.png" alt="Login mongodb" /></p>
<p><strong><em>Create a Project</em></strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eam85s6jpvmbbc3s2ued.png" alt="Creating Project" /></p>
<p><strong><em>Building a database</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635322728717-image-resized.png" alt="Building database" /></p>
<p><strong><em>Creating a cluster</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635322799518-image-resized.png" alt="Creating a clustre" /></p>
<p><strong><em>Selecting a cloud service provider</em></strong>
<img src="https://aviyel.com/assets/uploads/files/1635322998309-image-resized.png" alt="Cloud service provider" /></p>
<p><strong><em>Make a cluster and wait for the cluster to be built before proceeding (usually takes around 5 -10 minutes)</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635323127566-image-resized.png" alt="Making a clusture" /></p>
<p><strong><em>Allow access from anywhere by clicking connect. Then IP address should be added.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635323200442-image-resized.png" alt="Allow IP access" /></p>
<p><strong><em>In the database, create a user. You'll need the username and password for the MongoDB URI and finally create a database user.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635323489283-image-resized.png" alt="Creating a user" /></p>
<p><strong><em>Now, select the Choose a connection method.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635323638076-image-resized.png" alt="Connection method" /></p>
<p><strong><em>Connect your application by clicking on it and finally select the correct driver and version.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635323727857-image-resized.png" alt="Connecting application" /></p>
<p>Insert mongodb+srv into the .env file.</p>
<pre><code><span class="hljs-attr">PORT</span>=<span class="hljs-number">4000</span>
<span class="hljs-attr">DATABASE_URL</span>=mongodb+srv://pramit:&lt;password&gt;@cluster0.qjvl6.mongodb.net/myFirstDatabase?retryWrites=<span class="hljs-literal">true</span>&amp;w=majority
</code></pre><p>Now open the database.js file located inside the configurations folder and make the modifications listed below.</p>
<p><strong><em>Import Mongoose module.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635326087026-image.png" alt="Import Mongoose module" /></p>
<p><strong><em>Import dotenv package and configure it. Create DATABASE_URL inside env file and add your credential inside it and then you are able to import it from the .env file.</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635326262004-image-resized.png" alt="env file" /></p>
<p><strong><em>Importing dotenv module</em></strong></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635326299401-image.png" alt="Importing dotenv" /></p>
<p>Define the databaseConfiguration method for establishing a database connection.
The databaseConfiguration method should be exported and called in main.js.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635326407674-image.png" alt="db config" /></p>
<p>Now, database.js file should resemble something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635394994415-image.png" alt="database" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//database.js</span>

<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);
dotenv.config();

<span class="hljs-keyword">const</span> databaseURL = process.env.DATABASE_URL;

<span class="hljs-keyword">const</span> databaseConfiguration = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> mongoose.connect(databaseURL, {
      <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
    });
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Database connected'</span>);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
    process.exit(<span class="hljs-number">1</span>);
  }
};

<span class="hljs-built_in">module</span>.exports = databaseConfiguration;
</code></pre>
<p>Add the following changes on main.js file</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635395025087-image.png" alt="main js" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// main.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);
<span class="hljs-keyword">const</span> databaseConfiguration = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./configurations/database.js'</span>);

<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);

dotenv.config();

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;

<span class="hljs-comment">//connecting to the mongodb database</span>
databaseConfiguration();

<span class="hljs-comment">// add the middlewares</span>
app.use(express.json({ <span class="hljs-attr">extended</span>: <span class="hljs-literal">false</span> }));
app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> res.send(<span class="hljs-string">'&lt;h1&gt;Server is up and running&lt;/h1&gt;'</span>));

<span class="hljs-comment">// listen</span>
app.listen(PORT, <span class="hljs-function">() =&gt;</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${PORT}</span>`</span>)
);
</code></pre>
<h3 id="heading-adding-database-schema">Adding database schema:</h3>
<p>Add a models.js file inside the models folder. We will define the entire database schema inside this particular file.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8svtc63c56jnrk3mmni.png" alt="models js" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// models.js</span>
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> TodoListSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
  },
  <span class="hljs-attr">description</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
  },
  <span class="hljs-attr">date</span>: {
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,
  },
});

<span class="hljs-keyword">const</span> Todo = mongoose.model(<span class="hljs-string">'todo'</span>, TodoListSchema);

<span class="hljs-built_in">module</span>.exports = Todo;
</code></pre>
<p>Defining the entire endpoint of our API</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635395081033-image.png" alt="Todo routes" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//todo.routes.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-keyword">const</span> {
  listAllTodo,
  createOneTodo,
  updateOneTodo,
  deleteTodo,
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../controllers/todo.controller.js"</span>);

router.get(<span class="hljs-string">"/"</span>, listAllTodo);

router.post(<span class="hljs-string">"/"</span>, createOneTodo);

router.put(<span class="hljs-string">"/:id"</span>, updateOneTodo);

router.delete(<span class="hljs-string">"/:id"</span>, deleteTodo);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<h3 id="heading-defining-the-methods-for-endpoint">Defining the methods for endpoint</h3>
<p>The methods for the endpoints will be defined in the controllers folder and inside controllers.js file.</p>
<p>Now open the controllers.js file located inside the controllers folder and make the modifications listed below.
<img src="https://aviyel.com/assets/uploads/files/1635395105031-image.png" alt="Controllers" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//controllers.js</span>

<span class="hljs-keyword">const</span> AppTodo = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/models.js"</span>);

<span class="hljs-built_in">exports</span>.createOneTodo = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  AppTodo.create(req.body)
    .then(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log({ todo });
      res.json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Cheers!! You have successfully added TODO"</span>,
        todo,
      });
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      res.status(<span class="hljs-number">404</span>).json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Sorry your todo list cannot be added"</span>,
        <span class="hljs-attr">error</span>: err.message,
      });
    });
};

<span class="hljs-built_in">exports</span>.listAllTodo = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  AppTodo.find()
    .then(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log({ todo });
      res.json(todo);
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      res
        .status(<span class="hljs-number">404</span>)
        .json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"There isnt any todo available"</span>, <span class="hljs-attr">error</span>: err.message });
    });
};

<span class="hljs-built_in">exports</span>.updateOneTodo = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  AppTodo.findByIdAndUpdate(req.params.id, req.body)
    .then(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log({ todo });
      <span class="hljs-keyword">return</span> res.json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Cheers!! You have successfully updated TODO"</span>,
        todo,
      });
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      res.status(<span class="hljs-number">404</span>).json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Sorry your todo list cannot be updated"</span>,
        <span class="hljs-attr">error</span>: err.message,
      });
    });
};

<span class="hljs-built_in">exports</span>.deleteTodo = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  AppTodo.findByIdAndRemove(req.params.id, req.body)
    .then(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log({ todo });
      res.json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Cheers!! You have successfully deleted your TODO"</span>,
        todo,
      });
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
      res.status(<span class="hljs-number">404</span>).json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Sorry your todo is not there"</span>,
        <span class="hljs-attr">error</span>: err.message,
      });
    });
};
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635328123346-image-resized.png" alt="methods" /></p>
<p>Finally, add the endpoint to the main.js file. Also, don't forget to include the cors so that we can make API calls from the frontend application. As a result, your main.js file should look something like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635395025087-image.png" alt="Main js" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//main.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> databaseConfiguration = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./configurations/database.js"</span>);
<span class="hljs-keyword">const</span> todo = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./routes/todo.routes.js"</span>);

<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>);

dotenv.config();

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;

<span class="hljs-comment">//connecting to  mongodb </span>
databaseConfiguration();

<span class="hljs-comment">//adding cors</span>
app.use(cors({ <span class="hljs-attr">origin</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">credentials</span>: <span class="hljs-literal">true</span> }));

<span class="hljs-comment">// adding  middlewares</span>
app.use(express.json({ <span class="hljs-attr">extended</span>: <span class="hljs-literal">false</span> }));
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span>
  res.send(<span class="hljs-string">"Hello there!! Cheers !! The server is up and running"</span>)
);

<span class="hljs-comment">// using the todo routes</span>
app.use(<span class="hljs-string">"/api/todoapp"</span>, todo);

<span class="hljs-comment">// listen</span>
app.listen(PORT, <span class="hljs-function">() =&gt;</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${PORT}</span>`</span>)
);
</code></pre>
<p>After restarting the server, you should see something similar to this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635328244798-image.png" alt="server running" /></p>
<p>Finally, start both the client and the server, and you should see something similar to this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635343378933-image-resized.png" alt="Demo" /></p>
<p>The complete source code for the application can be found here:</p>
<p><a target="_blank" href="https://github.com/pramit-marattha/MERN-awesome-crud">https://github.com/pramit-marattha/MERN-awesome-crud</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This blog tutorial demonstrated how to use the MERN stack to build a basic React Todo CRUD application. This concise guide went over the essential MERN stack topics one by one, focusing on each one carefully and discreetly. You learned how to establish a basic react app, style it with necessary npm packages, and make HTTP queries related to the crud app; we also set up the node back-end server in the react app using necessary npm packages. We used MongoDB to save and store the data and learned how to use the React platform to store the data, and this lesson might have been very helpful for you if you are new to MERN stack development. Cheers!!</p>
<p>Happy coding !!</p>
<p>Main article available here =&gt; https://aviyel.com/post/1278</p>
<p>Happy Coding!! </p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Join Aviyel's Discord =&gt; <a target="_blank" href="https://discord.gg/TbfZmbvnN5">Aviyel's world</a></p>
<p>Twitter =&gt;[https://twitter.com/AviyelHq]</p>
]]></content:encoded></item><item><title><![CDATA[Build a Full-Stack Notebook App using React and Firebase 📓 🔥]]></title><description><![CDATA[In this blog tutorial, we are going to set up and build full-stack notebook applications using react.js from absolutely scratch. We will be creating everything from absolute scratch. However, before we begin, the final version of the app should resem...]]></description><link>https://pramitmarattha.com.np/build-a-full-stack-notebook-app-using-react-and-firebase</link><guid isPermaLink="true">https://pramitmarattha.com.np/build-a-full-stack-notebook-app-using-react-and-firebase</guid><category><![CDATA[React]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Mon, 29 Nov 2021 13:14:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638191549854/b9jiYW8Xs.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog tutorial, we are going to set up and build full-stack notebook applications using react.js from absolutely scratch. We will be creating everything from absolute scratch. However, before we begin, the final version of the app should resemble this. You can also view the application's final live version.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635745062282-image-resized.png" alt="Demo" /></p>
<p><a target="_blank" href="https://react-firebase-notebook.netlify.app/">https://react-firebase-notebook.netlify.app/</a></p>
<h2 id="heading-configuring-react-application">Configuring react application</h2>
<p>Let's get our first react application up and running. So, if you don't already have Node.js installed on your PC, the first thing you need to do is install it. To do so, go to the official Node.js website and download the relevant and necessary version. We require node js in order to use the NPM feature of the node package manager.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635484547846-image.png" alt="Creating a directory" /></p>
<p>Now create a folder and open it in your preferred coding editor. I'll be using VScode. Next, open the integrated terminal and type npx create-react-app react-firebase-notebook The app will be named react-firebase-notebook and will be created in the current directory using this command.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635495286432-image-resized.png" alt="npx script" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635484616277-image-resized.png" alt="create react app" /></p>
<p>Installing it normally only takes a few minutes. Normally, we would use npm to get packages into a project, but here we're using npx, the package runner, which will download and configure everything for us so that we can get started with an excellent template right away. Now it's time to start our development server, so simply run npm start and react-app will open in the browser immediately.</p>
<p>Now it's time to look into the file and folder structure that create-react-app provides. All of our node dependencies are stored in a subdirectory called node module. Then there's the public folder, where the index.html file is the only thing that matters. So far, it appears that this is a regular HTML file, replete with head, body, and meta tags. Inside our body tag, you'll find a div with the id root, followed by the fallback noscript tag, which will only be visible if the user's browser doesn't support javascript.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635495506335-image-resized.png" alt="Index html" /></p>
<p>So you're undoubtedly curious about the source of the content. Remember that all of our source code is housed in the src folder, and react will inject it into the root div element. Look in the src folder for some stylesheets, javascript scripts, and SVG files.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635495594965-image.png" alt="Source Directory" /></p>
<p>Now, head over to our App.js file</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635498569761-image-resized.png" alt="App js" /></p>
<p>In this situation, we're simply using regular javascript to import react from react and logo from our logo. Following that, we have a regular javascript function called App, which is known as a functional component in react, and this function returns a react-element that looks like HTML but is actually a jsx, as you can see there is a div tag with a className of APP, which we can't say class by itself because the class is a reserved word in javascript, so we have to use className in jsx. Following that, we have the header and then the image, and notice on the image source that we have our logo, which is actually a javascript variable that we imported at the top, so we must surround it with curly brackets in order to use the javascript within JSX, and then we have a paragraph, an anchor tag, and that's it for this component.</p>
<p>Let's take a look at the index.js file now.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635498773058-image-resized.png" alt="index.js" /></p>
<p>So, we're importing react from react again, and this time we're also importing react-dom, and then we're importing the CSS stylesheet file, and finally, we're importing App from App.js, which is the file we just discussed, and there's also service worker, which is used to make your app work completely offline. After that, we use ReactDom.render, which takes two parameters. The first parameter is the jsx object, which contains our user-defined components (react strict mode is a react defined component, whereas App is a user-defined component), and the second parameter is document.getElementById('root'), which targets the root div in our index.html file and is how we access the content in our webpage. Always keep in mind that ReactDom renders our content into our index.html file's root div.</p>
<h2 id="heading-crafting-our-notebook-application">Crafting our notebook application.</h2>
<p>Let's start from the ground up and build a small notebook application in react, but before, let's make a prototype or mindmap of our end product. So, here is how our finished app will look.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635500653386-image-resized.png" alt="Demo" /></p>
<p>We must first tidy up our projects by eliminating some of the files provided by create-react-app before we can begin creating them. After you've cleaned up your src files, they should look like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635500814441-image.png" alt="File cleanup" /></p>
<p>Let's get started configuring firebase on our project now that we've finished configuring react.</p>
<h2 id="heading-what-is-firebase">What is Firebase?</h2>
<p>Firebase is a serverless mobile and web application platform for Web developers. This implies we won't have to start from the ground up when it comes to setting up a server. We don't need to buy and configure a server to serve our webpage to the World Wide Web because Firebase is a pre-configured server. We already have all of those functions in place. All we have to do now is make use of their backend services. Backend activities are straightforward with Firebase. Let's set up these tools so that you have a general notion of what we'll be using for our project.</p>
<h2 id="heading-setting-up-firebase">Setting up Firebase</h2>
<p>You'll need a Google account to set up Firebase. Sign up for a Firebase account. Then, from the top bar, select Go to Console to access the Firebase console, which should resemble something like this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504085628-image-resized.png" alt="Firebase login" /></p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504118957-image-resized.png" alt="Firebase Console" /></p>
<p>We can now create a new project in firebase.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504343863-image-resized.png" alt="new project" /></p>
<p>We are making a project with the name: React-Firebase-Notebook . Give your app name whatever you want.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504501487-image-resized.png" alt="Google analytics" /></p>
<p>You have the option of enabling or disabling Google Analytics.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504588315-image-resized.png" alt="Configure google analytics" /></p>
<p>Now, select the google analytics account. So, a new Google Analytics property will be generated in your chosen Google Analytics account and linked to your Firebase project when you build the project. This link will allow data to move back and forth between the products.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504736867-image-resized.png" alt="Provisioning resources" /></p>
<p>Creating a project may take a few seconds.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635504776418-image-resized.png" alt="project creation completed" /></p>
<p>Now, if we click continue, we'll be sent to our new React-Firebase-Notebook project. This is a free tier, and it's extremely generous because it allows you so much free and awesome stuff to try.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635587094149-image-resized.png" alt="Dashboard" /></p>
<p>Now the only thing that we need on this project overview page is to click on the “Add firebase to web app” and then register the app name.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635587862849-image-resized.png" alt="Register app" /></p>
<p>After that, you'll have access to the API key, the database URL, the auth domain, the app ID, and a ton of other cool stuff.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635588067149-image-resized.png" alt="Firebase Config" /></p>
<p>We'll use that config to initialize our Firebase application, so copy it and put it someplace in your notepad or any other program. After that, simply click next, and you'll be given CLI commands to install Firebase, which you should copy somewhere on the notepad as well.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635588285120-image-resized.png" alt="Firebase CLI commands" /></p>
<p>Finally, you will be given the command for deploying the program, which you should copy and store somewhere on your notepad.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635588495342-image-resized.png" alt="Firebase Deploy command" /></p>
<p>Continue to console now that you've finished configuring the Firebase project.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700905239-image.png" alt="App component" /></p>
<p>Let's return to our react application and open the App.js file, where we'll copy and paste the firebase config.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"--------------------"</span>,
};

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello there<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now let's head over to our terminal and make sure we're in the right project folder before installing Firebase. It might take few minutes to get installed.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635665435922-image.png" alt="Firebase Installation" /></p>
<p>After that, your package.json file should resemble something like this.</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"name"</span>:<span class="hljs-string">"react-firebase-notebook"</span>,
   <span class="hljs-attr">"version"</span>:<span class="hljs-string">"0.1.0"</span>,
   <span class="hljs-attr">"private"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-attr">"dependencies"</span>:{
      <span class="hljs-attr">"@testing-library/jest-dom"</span>:<span class="hljs-string">"^5.11.4"</span>,
      <span class="hljs-attr">"@testing-library/react"</span>:<span class="hljs-string">"^11.1.0"</span>,
      <span class="hljs-attr">"@testing-library/user-event"</span>:<span class="hljs-string">"^12.1.10"</span>,
      <span class="hljs-attr">"firebase"</span>:<span class="hljs-string">"^9.2.0"</span>,
      <span class="hljs-attr">"react"</span>:<span class="hljs-string">"^17.0.2"</span>,
      <span class="hljs-attr">"react-dom"</span>:<span class="hljs-string">"^17.0.2"</span>,
      <span class="hljs-attr">"react-scripts"</span>:<span class="hljs-string">"4.0.3"</span>,
      <span class="hljs-attr">"web-vitals"</span>:<span class="hljs-string">"^1.0.1"</span>
   },
   <span class="hljs-attr">"scripts"</span>:{
      <span class="hljs-attr">"start"</span>:<span class="hljs-string">"react-scripts start"</span>,
      <span class="hljs-attr">"build"</span>:<span class="hljs-string">"react-scripts build"</span>,
      <span class="hljs-attr">"test"</span>:<span class="hljs-string">"react-scripts test"</span>,
      <span class="hljs-attr">"eject"</span>:<span class="hljs-string">"react-scripts eject"</span>
   },
   <span class="hljs-attr">"eslintConfig"</span>:{
      <span class="hljs-attr">"extends"</span>:[
         <span class="hljs-string">"react-app"</span>,
         <span class="hljs-string">"react-app/jest"</span>
      ]
   },
   <span class="hljs-attr">"browserslist"</span>:{
      <span class="hljs-attr">"production"</span>:[
         <span class="hljs-string">"&gt;0.2%"</span>,
         <span class="hljs-string">"not dead"</span>,
         <span class="hljs-string">"not op_mini all"</span>
      ],
      <span class="hljs-attr">"development"</span>:[
         <span class="hljs-string">"last 1 chrome version"</span>,
         <span class="hljs-string">"last 1 firefox version"</span>,
         <span class="hljs-string">"last 1 safari version"</span>
      ]
   }
}
</code></pre>
<p>Now that Firebase is installed, let's import all (*) of the firebase's exports.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>
</code></pre>
<p>Also, don't forget to initialize your Firebase configuration.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700905239-image.png" alt="App component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//App.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"--------------------"</span>,
};
firebase.initializeApp(firebaseConfig);

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello there<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>After we've installed and setup all of the necessary components for this project, we'll go ahead and create it. To do so, we'll need to make a few changes to our App.js file. The first thing we'll do is put up our Navbar section, so inside our src folder, create a components folder, and inside that components folder, create another folder called Navbar, with three files titled index.js , Navbar.js and Navbar.css your folder structure should resemble like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700866667-image.png" alt="Navbar component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Navbar/index.js</span>
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./Navbar.js"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>Let's get started on crafting our navbar section.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Navbar/Navbar.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./Navbar.css"</span>;

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"heading"</span>&gt;</span>📓 React firebase Notebook <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>Now it's time to give our Navbar some styling.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/*components/Navbar/Navbar.css */</span>
 .navbar {
     <span class="hljs-attr">display</span>: flex;
     justify-content: center;
     align-items: center;
     width: <span class="hljs-number">99</span>vw;
     height: <span class="hljs-number">70</span>px;
     background: rgba( <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.15</span> );
     box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">8</span>px <span class="hljs-number">32</span>px <span class="hljs-number">0</span> rgba( <span class="hljs-number">31</span>, <span class="hljs-number">38</span>, <span class="hljs-number">135</span>, <span class="hljs-number">0.37</span> );
     backdrop-filter: blur( <span class="hljs-number">7.5</span>px );
     -webkit-backdrop-filter: blur( <span class="hljs-number">7.5</span>px );
     border-radius: <span class="hljs-number">20</span>px;
     border: <span class="hljs-number">1</span>px solid rgba( <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.18</span> );
}
 .navbar .heading {
     <span class="hljs-attr">color</span>: #fd5252;
     font-size: <span class="hljs-number">20</span>px;
     font-weight: <span class="hljs-number">700</span>;
     font-family: <span class="hljs-string">'Poppins'</span>, sans-serif;
}
</code></pre>
<p>Let's now import and initialize our Navbar component within the App component</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700905239-image.png" alt="App component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"--------------------"</span>,
};
firebase.initializeApp(firebaseConfig);

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><img src="https://aviyel.com/assets/uploads/files/1635704032436-image.png" alt="NoteAdd Component" /></p>
<p>Its time to create another component for adding notes so for that create another folder called NoteAdd, with three files titled index.js , NoteAdd.js and NoteAdd.css your folder structure should resemble like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635703346321-image.png" alt="Folder Structure" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/NoteAdd/index.js</span>
<span class="hljs-keyword">import</span> NoteAdd <span class="hljs-keyword">from</span> <span class="hljs-string">"./NoteAdd"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NoteAdd
</code></pre>
<p>Let's get started on crafting our skeleton for our NoteAdd section</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/NoteAdd/NoteAdd.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./NoteAdd.css"</span>;

<span class="hljs-keyword">const</span> NoteAdd = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Add a New Note<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-header"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"noteadd-header"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Note Title"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"noteadd-description"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-description"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Note Description"</span>
          &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-button"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add a Note<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NoteAdd;
</code></pre>
<p>Now it's time to give our NoteAdd section some styling.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* components/NoteAdd/NoteAdd.css */</span>
 <span class="hljs-selector-class">.noteadd</span> {
     <span class="hljs-attribute">display</span>: block;
     <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
     <span class="hljs-attribute">max-width</span>: <span class="hljs-number">500px</span>;
     <span class="hljs-attribute">margin</span>: <span class="hljs-number">10px</span> auto;
}
 <span class="hljs-selector-class">.noteadd</span> <span class="hljs-selector-tag">h1</span> {
     <span class="hljs-attribute">display</span>: flex;
     <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.15</span>);
     <span class="hljs-attribute">justify-content</span>: center;
     <span class="hljs-attribute">align-items</span>: center;
     <span class="hljs-attribute">color</span>: <span class="hljs-number">#8661d1</span>;
     <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"poppins"</span>;
     <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}
 <span class="hljs-selector-tag">input</span> {
     <span class="hljs-attribute">border-style</span>: none;
     <span class="hljs-attribute">background</span>: transparent;
     <span class="hljs-attribute">outline</span>: none;
}
 <span class="hljs-selector-tag">textarea</span> {
     <span class="hljs-attribute">border-style</span>: none;
     <span class="hljs-attribute">background</span>: transparent;
     <span class="hljs-attribute">outline</span>: none;
}
 <span class="hljs-selector-class">.noteadd-header</span> {
     <span class="hljs-attribute">display</span>: flex;
     <span class="hljs-attribute">justify-content</span>: center;
     <span class="hljs-attribute">align-items</span>: center;
     <span class="hljs-attribute">flex-direction</span>: row;
     <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
     <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
     <span class="hljs-attribute">height</span>: <span class="hljs-number">10px</span>;
     <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
     <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
     <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
     <span class="hljs-attribute">background</span>: white;
}
 <span class="hljs-selector-class">.noteadd-header</span> <span class="hljs-selector-tag">input</span> {
     <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
     <span class="hljs-attribute">color</span>: white;
     <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.8rem</span>;
     <span class="hljs-attribute">line-height</span>: <span class="hljs-number">2.4rem</span>;
     <span class="hljs-attribute">vertical-align</span>: middle;
}
 <span class="hljs-selector-class">.noteadd-description</span> {
     <span class="hljs-attribute">position</span>: relative;
     <span class="hljs-attribute">display</span>: flex;
     <span class="hljs-attribute">flex-direction</span>: row;
     <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
     <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
     <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
     <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
     <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
     <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
     <span class="hljs-attribute">background</span>: white;
}
 <span class="hljs-selector-class">.noteadd-header</span> <span class="hljs-selector-tag">textarea</span> {
     <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
     <span class="hljs-attribute">color</span>: white;
     <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.8rem</span>;
     <span class="hljs-attribute">line-height</span>: <span class="hljs-number">2.4rem</span>;
     <span class="hljs-attribute">vertical-align</span>: middle;
}
 <span class="hljs-selector-class">.noteadd</span> <span class="hljs-selector-class">.form-group</span> {
     <span class="hljs-attribute">display</span>: flex;
     <span class="hljs-attribute">flex-direction</span>: column;
     <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">15px</span>;
     <span class="hljs-attribute">justify-content</span>: center;
}
 <span class="hljs-selector-class">.noteadd-button</span> {
     <span class="hljs-attribute">display</span>: flex;
     <span class="hljs-attribute">justify-content</span>: center;
     <span class="hljs-attribute">align-items</span>: center;
}
 <span class="hljs-selector-tag">button</span> {
     <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">15px</span>;
     <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
     <span class="hljs-attribute">text-align</span>: center;
     <span class="hljs-attribute">cursor</span>: pointer;
     <span class="hljs-attribute">outline</span>: none;
     <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
     <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#8661d1</span>;
     <span class="hljs-attribute">border</span>: none;
     <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">15px</span>;
     <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgb</span>(<span class="hljs-number">109</span>, <span class="hljs-number">57</span>, <span class="hljs-number">129</span>);
}
 <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
     <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#906ed3</span>;
}
 <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:active</span> {
     <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fd5252e5</span>;
     <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgb</span>(<span class="hljs-number">212</span>, <span class="hljs-number">93</span>, <span class="hljs-number">93</span>);
     <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(<span class="hljs-number">4px</span>);
}
</code></pre>
<p>Let's now import and initialize our NoteAdd component within the App component</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700905239-image.png" alt="App component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>;
<span class="hljs-keyword">import</span> NoteAdd <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/NoteAdd"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"--------------------"</span>,
};
firebase.initializeApp(firebaseConfig);

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"note-section"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NoteAdd</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Create a useState() hook in your NoteAdd.js file since this hook will allow us to integrate the state into our functional component. Unlike state in class components, useState() doesn't work with object values. If necessary, we can create numerous react hooks for multiple variables by using primitives directly.</p>
<pre><code><span class="hljs-keyword">const</span> [state, setState] = useState(initialState);
</code></pre><p><img src="https://aviyel.com/assets/uploads/files/1635730004522-image.png" alt="use state hook" /></p>
<p>Hooks must always be declared at the beginning of a function in React. This also aids in the component's state maintenance as well as preservation between renderings.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635730529821-image.png" alt="States" /></p>
<p>Now that we have the tilte and descripton as a state variable, we can use the setter function to modify them in functions. So, let us build the second section of the application that allows us to add notes onto our firebase real-time database. We'll make a separate component for displaying the notes. NoteAdd component includes a form with an input field where the user can enter the title and description of the new notes. It also includes a button for adding the notes to the list. A variable is also required to store the title as well as a description as the user types in the input text box. To accomplish this, we will create a title and description state that is unique to this component and also we will be pushing the value of title and description present on that state to our firebase real-time database. The NoteAdd component will then look like this:</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635704032436-image.png" alt="NoteAdd component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/NoteAdd/NoteAdd.js</span>
<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./NoteAdd.css"</span>;

<span class="hljs-keyword">const</span> NoteAdd = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleTitleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setTitle(event.target.value);
  };

  <span class="hljs-keyword">const</span> handleDescriptionChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setDescription(event.target.value);
  };

  <span class="hljs-keyword">const</span> addNote = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (title !== <span class="hljs-string">""</span> &amp;&amp; description !== <span class="hljs-string">""</span>) {
      firebase.database().ref(<span class="hljs-string">"notebook"</span>).push({
        <span class="hljs-attr">title</span>: title,
        <span class="hljs-attr">description</span>: description,
      });
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Add a New Note<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-header"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"noteadd-header"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Note Title"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{title}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(val)</span> =&gt;</span> handleTitleChange(val)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"noteadd-description"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-description"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Note Description"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{description}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(val)</span> =&gt;</span> handleDescriptionChange(val)}
          &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"noteadd-button"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> addNote()}&gt;Add a Note<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> NoteAdd;
</code></pre>
<p>Now that you've changed your NoteAdd component, you'll want to go to your Firebase console and select realtime database.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635668188592-image-resized.png" alt="Database options" /></p>
<p>You'll be prompted to configure the database location, so choose your preferred location and then click next.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635668204704-image-resized.png" alt="Setting up rules" /></p>
<p>Following that, you'll be prompted to choose between test mode and locked mode for the Firebase rules. Select either of them and click “next” to proceed.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635668263934-image-resized.png" alt="updating rules" /></p>
<p>Finally, now that you've successfully created your Firebase real-time database, let's update our security rules. We're not going to implement any security here, so simply set "read" and "write" to "true."</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635745675837-image.png" alt="Notebook component" /></p>
<p>Its time to create another component for displaying notebooks so for that create another folder called Notebook, with three files titled index.js , Notebook.js and Notebook.css inside it. So, your folder structure should resemble like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635745361888-image.png" alt="Folder structure" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Notebook/index.js</span>
<span class="hljs-keyword">import</span> Notebook <span class="hljs-keyword">from</span> <span class="hljs-string">"./Notebook"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Notebook;
</code></pre>
<p>Let's get started on crafting our skeleton for our NoteAdd section</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Notebook/NoteAdd.js</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./Notebook.css"</span>;

<span class="hljs-keyword">const</span> Notebook = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> deleteNotebook = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
    firebase.database().ref(<span class="hljs-string">"notebook"</span>).child(id).remove();
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notebook-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notebook"</span>&gt;</span>
          {props.notebook.map((note, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notebookInfo"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{note.id}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notebookInfo-title"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{note.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"remove"</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteNotebook(note.id)}
                  &gt;
                    🗑️
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"notebookInfo-description"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{note.description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Notebook;
</code></pre>
<p>Now it's time to give our Notebook section some styling.</p>
<pre><code class="lang-javascript">.notebook {
  <span class="hljs-attr">display</span>: grid;
  grid-template-columns: <span class="hljs-number">1</span>fr;
  grid-gap: <span class="hljs-number">20</span>px;
  padding: <span class="hljs-number">20</span>px;
}
.notebook .notebookInfo {
  <span class="hljs-attr">background</span>: rgba(<span class="hljs-number">209</span>, <span class="hljs-number">97</span>, <span class="hljs-number">175</span>, <span class="hljs-number">0.25</span>);
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">8</span>px <span class="hljs-number">32</span>px <span class="hljs-number">0</span> rgba(<span class="hljs-number">135</span>, <span class="hljs-number">31</span>, <span class="hljs-number">100</span>, <span class="hljs-number">0.37</span>);
  backdrop-filter: blur(<span class="hljs-number">2.5</span>px);
  border-radius: <span class="hljs-number">20</span>px;
  border: <span class="hljs-number">1</span>px solid rgba(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.18</span>);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: <span class="hljs-number">2</span>rem;
  min-height: <span class="hljs-number">1</span>rem;
  width: <span class="hljs-number">20</span>rem !important;
  margin: <span class="hljs-number">0</span>rem auto;
}

.notebook .notebookInfo .notebookInfo-title {
  <span class="hljs-attr">background</span>: rgba(<span class="hljs-number">212</span>, <span class="hljs-number">134</span>, <span class="hljs-number">98</span>, <span class="hljs-number">0.25</span>);
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">8</span>px <span class="hljs-number">32</span>px <span class="hljs-number">0</span> rgba(<span class="hljs-number">135</span>, <span class="hljs-number">31</span>, <span class="hljs-number">130</span>, <span class="hljs-number">0.37</span>);
  border-radius: <span class="hljs-number">15</span>px;
  border: <span class="hljs-number">1</span>px solid rgba(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.18</span>);
  backdrop-filter: blur(<span class="hljs-number">2.5</span>px);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.notebookInfo-title h3 {
  padding-left: <span class="hljs-number">1</span>rem;
}

.notebookInfo-title .remove {
  padding-right: <span class="hljs-number">1</span>rem;
}

.notebook .notebookInfo .notebookInfo-title {
  <span class="hljs-attr">color</span>: #f3f3f3;
  margin: <span class="hljs-number">0</span>;
  padding: <span class="hljs-number">0</span>;
  font-family: <span class="hljs-string">"Poppins"</span>;
}

.notebook .notebookInfo .notebookInfo-title .remove {
  <span class="hljs-attr">color</span>: #ff0000;
  font-size: <span class="hljs-number">24</span>px;
  font-weight: <span class="hljs-number">700</span>;
}

.notebook .notebookInfo .notebookInfo-description {
  <span class="hljs-attr">padding</span>: <span class="hljs-number">10</span>px;
}

.remove {
  <span class="hljs-attr">cursor</span>: pointer;
}

@media screen and (min-width: <span class="hljs-number">768</span>px) {
  .notebook {
    grid-template-columns: repeat(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>fr);
  }
}
</code></pre>
<p>Let's now import and initialize our Notebook component within the App component but before that,  let’s dive into useEffect() hook. By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. To this effect, we set the document title, but we could also perform data fetching or call some other imperative API. Placing  useEffect() inside the component lets us access the count state variable (or any props) right from the effect. We don’t need a special API to read it — it’s already in the function scope. Hooks embrace JavaScript closures and avoid introducing React-specific APIs where JavaScript already provides a solution.useEffect() the hook is somewhat similar to the life-cycle methods that we are aware of for class components. It runs after every render of the component including the initial render. Hence it can be thought of as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount.If we want to control the behavior of when the effect should run (only on initial render, or only when a particular state variable changes), we can pass in dependencies to the effect to do so. This hook also provides a clean-up option to allow cleaning up of resources before the component is destroyed. basic syntax of the effect: useEffect(didUpdate) .</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635746105545-image.png" alt="useEffect Hooks" /></p>
<p>Let's make a function that adds and removes notes from the Firebase database, and then preserve it inside the useEffect hooks.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> updateNotes = <span class="hljs-function">() =&gt;</span> {
  firebase
    .database()
    .ref(<span class="hljs-string">"notebook"</span>)
    .on(<span class="hljs-string">"child_added"</span>, <span class="hljs-function">(<span class="hljs-params">snapshot</span>) =&gt;</span> {
      <span class="hljs-keyword">let</span> note = {
        <span class="hljs-attr">id</span>: snapshot.key,
        <span class="hljs-attr">title</span>: snapshot.val().title,
        <span class="hljs-attr">description</span>: snapshot.val().description,
      };
      <span class="hljs-keyword">let</span> notebook = noteBookData;
      notebook.push(note);
      setNoteBookData([...noteBookData]);
    });

  firebase
    .database()
    .ref(<span class="hljs-string">"notebook"</span>)
    .on(<span class="hljs-string">"child_removed"</span>, <span class="hljs-function">(<span class="hljs-params">snapshot</span>) =&gt;</span> {
      <span class="hljs-keyword">let</span> notebook = noteBookData;
      notebook = noteBookData.filter(<span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> note.id !== snapshot.key);
      setNoteBookData(notebook);
    });
};

useEffect(<span class="hljs-function">() =&gt;</span> {
  updateNotes();
}, []);
</code></pre>
<p>Finally, Import the Notebook as a component and pass the noteBookData as props.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635700905239-image.png" alt="App component" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/Notebook/Notebook.js</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/compat/app"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"firebase/compat/database"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>;
<span class="hljs-keyword">import</span> NoteAdd <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/NoteAdd"</span>;
<span class="hljs-keyword">import</span> Notebook <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Notebook"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-keyword">const</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"--------------------"</span>, 
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"--------------------"</span>,
  <span class="hljs-attr">measurementId</span>: <span class="hljs-string">"--------------------"</span>
};
firebase.initializeApp(firebaseConfig);

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [noteBookData, setNoteBookData] = useState([]);

  <span class="hljs-keyword">const</span> updateNotes = <span class="hljs-function">() =&gt;</span> {
    firebase
      .database()
      .ref(<span class="hljs-string">"notebook"</span>)
      .on(<span class="hljs-string">"child_added"</span>, <span class="hljs-function">(<span class="hljs-params">snapshot</span>) =&gt;</span> {
        <span class="hljs-keyword">let</span> note = {
          <span class="hljs-attr">id</span>: snapshot.key,
          <span class="hljs-attr">title</span>: snapshot.val().title,
          <span class="hljs-attr">description</span>: snapshot.val().description,
        };
        <span class="hljs-keyword">let</span> notebook = noteBookData;
        notebook.push(note);
        setNoteBookData([...noteBookData]);
      });

    firebase
      .database()
      .ref(<span class="hljs-string">"notebook"</span>)
      .on(<span class="hljs-string">"child_removed"</span>, <span class="hljs-function">(<span class="hljs-params">snapshot</span>) =&gt;</span> {
        <span class="hljs-keyword">let</span> notebook = noteBookData;
        notebook = noteBookData.filter(<span class="hljs-function">(<span class="hljs-params">note</span>) =&gt;</span> note.id !== snapshot.key);
        setNoteBookData(notebook);
      });
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    updateNotes();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"note-section"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">NoteAdd</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Notebook</span> <span class="hljs-attr">notebook</span>=<span class="hljs-string">{noteBookData}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Finally, let's incorporate more styles into our project. Now, go to your App.css file and update your style, or simply copy and paste the following CSS code.</p>
<pre><code class="lang-css">* {
     <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
     <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}
 <span class="hljs-selector-class">.app</span> {
     <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">linear-gradient</span>( to right, rgb(<span class="hljs-number">242</span>, <span class="hljs-number">112</span>, <span class="hljs-number">156</span>), <span class="hljs-built_in">rgb</span>(<span class="hljs-number">255</span>, <span class="hljs-number">148</span>, <span class="hljs-number">114</span>) );
     <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
     <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
     <span class="hljs-attribute">align-items</span>: center;
}
 <span class="hljs-selector-class">.note-section</span> {
     <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
}
</code></pre>
<p>If you followed all of the steps correctly, your project should look like this.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1635745062282-image-resized.png" alt="Demo" /></p>
<p>The full source code of the project can be found here.</p>
<p><a target="_blank" href="https://github.com/pramit-marattha/React-firebase-notebook">https://github.com/pramit-marattha/React-firebase-notebook</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this blog tutorial, we successfully created an awesome-looking notebook app that lets you add notes and save that notes on the database. From here, we can be extremely creative and come up with a variety of ways to improve the app while also honing or mastering your React and Firebase skills. If you found this to be very simple, experiment with the code and try to add more functionality like User Authentication functionality, personalized profiles of notes, notifications and so on. Cheers!! Happy coding!!</p>
<p>Main article available here =&gt; https://aviyel.com/post/1277</p>
<p>Happy Coding!! </p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Join Aviyel's Discord =&gt; <a target="_blank" href="https://discord.gg/TbfZmbvnN5">Aviyel's world</a></p>
<p>Twitter =&gt;[https://twitter.com/AviyelHq]</p>
]]></content:encoded></item><item><title><![CDATA[300+ React Interview Questions :fire: [Free PDF Download]]]></title><description><![CDATA[Do you wish to change careers for a more lucrative position? Or have you been putting in a lot of time and work in preparation for a weekend interview? Do you have any idea how many people are turned down for jobs because they just study for concepts...]]></description><link>https://pramitmarattha.com.np/300-react-interview-questions-fire-free-pdf-download</link><guid isPermaLink="true">https://pramitmarattha.com.np/300-react-interview-questions-fire-free-pdf-download</guid><category><![CDATA[React]]></category><category><![CDATA[interview]]></category><category><![CDATA[questions]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Wed, 17 Nov 2021 13:59:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637156931196/JE9ycfu1h.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you wish to change careers for a more lucrative position? Or have you been putting in a lot of time and work in preparation for a weekend interview? Do you have any idea how many people are turned down for jobs because they just study for concepts rather than the actual questions that will be asked? This time, try not to be that person. This is the most complete set of React JS interview questions you'll ever come across. It has a lot of often asked and important React JS interview questions and answers. Freshers, seasoned professionals, senior developers, and testers will benefit from a wide range of questions that cover not only the fundamentals of React JS but also the most advanced and challenging problems. This blog post will guide thoroughly for those who want to practice and enhance their react.js skills. I recommend that you read everything thoroughly beforehand and practice and sharpen your react knowledge.</p>
<h2 id="react-basics">React Basics</h2>
<h3 id="1-what-is-the-difference-between-element-and-component">1. What is the difference between Element and Component?</h3>
<p>An Element is a plain object describing what you want to appear on the screen in terms of the DOM nodes or other components. Elements can contain other Elements in their props. Creating a React element is cheap. Once an element is created, it is never mutated. The object representation of React Element would be as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> element = React.createElement(
  <span class="hljs-string">'div'</span>,
  {<span class="hljs-attr">id</span>: <span class="hljs-string">'login-btn'</span>},
  <span class="hljs-string">'Login'</span>
)
</code></pre>
<p>The above React.createElement() function returns an object:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">type</span>: <span class="hljs-string">'div'</span>,
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">children</span>: <span class="hljs-string">'Login'</span>,
    <span class="hljs-attr">id</span>: <span class="hljs-string">'login-btn'</span>
  }
}
</code></pre>
<p>And finally, it renders to the DOM using ReactDOM.render():</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">'login-btn'</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Whereas a component can be declared in several different ways. It can be a class with a render() method or it can be defined as a function. In either case, it takes props as an input, and returns a JSX tree as the output:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ onLogin }</span>) =&gt;</span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>'<span class="hljs-attr">login-btn</span>'} <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onLogin}</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>Then JSX gets transpiled to a React.createElement() function tree:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ onLogin }</span>) =&gt;</span> React.createElement(
  <span class="hljs-string">'div'</span>,
  { <span class="hljs-attr">id</span>: <span class="hljs-string">'login-btn'</span>, <span class="hljs-attr">onClick</span>: onLogin },
  <span class="hljs-string">'Login'</span>
)
</code></pre>
<h3 id="2-how-to-create-components-in-react">2. How to create components in React?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636961584727-image.png" alt="components" /></p>
<p>There are two possible ways to create a component.</p>
<ul>
<li>Function Components: This is the simplest way to create a component. Those are pure JavaScript functions that accept props object as first parameter and return React elements:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeting</span>(<span class="hljs-params">{ message }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{`Hello, ${message}`}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
}
</code></pre>
<ul>
<li>Class Components: You can also use ES6 class to define a component. The above function component can be written as:<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeting</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
render() {
<span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{`Hello, ${this.props.message}`}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
}
}
</code></pre>
</li>
</ul>
<h3 id="3-what-are-pure-components">3. What are Pure Components?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636961714521-image.png" alt="pure components" /></p>
<p>React.PureComponent is exactly the same as React.Component except that it handles the shouldComponentUpdate() method for you. When props or state changes, PureComponent will do a shallow comparison on both props and state. Components on the other hand won't compare current props and state to next out of the box. Thus, the component will re-render by default whenever shouldComponentUpdate is invoked.</p>
<h3 id="4-what-is-the-state-in-react">4. What is the state in React?</h3>
<p>The stateof a component is an object that holds some information that may change over the lifetime of the component. We should always try to make our state as simple as possible and minimize the number of stateful components.Let's create a user component with a message state,</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props)

    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">message</span>: <span class="hljs-string">'Welcome to React world'</span>
    }
  }
  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{this.state.message}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
  }
}
</code></pre>
<p>State is similar to props, but it is private and fully controlled by the component. i.e, It is not accessible to any other component until the owner component decides to pass it.</p>
<ol>
<li>What are props in React?</li>
</ol>
<p>Propsare inputs to components. They are single values or objects containing a set of values that are passed to components on creation using a naming convention similar to HTML-tag attributes. They are data passed down from a parent component to a child component.The primary purpose of props in React is to provide the following component functionality:</p>
<ul>
<li><p>Pass custom data to your component.</p>
</li>
<li><p>Trigger state changes.</p>
</li>
<li><p>Use via this.props.reactProp inside component render() method</p>
</li>
</ul>
<p>For example, let us create an element with reactProp property:</p>
<pre><code class="lang-javascript">&lt;Element reactProp={<span class="hljs-string">'1'</span>} /&gt;
</code></pre>
<p>This react pro (or whatever you came up with) name then becomes a property attached to React's native props object which originally already exists on all components created using React library.</p>
<pre><code class="lang-javascript">props.reactProp
</code></pre>
<h3 id="6-what-is-the-difference-between-state-and-props">6. What is the difference between state and props?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636962128625-image.png" alt="state vs props" /></p>
<p>Both props and state are plain JavaScript objects. While both of them hold information that influences the output of render, they are different in their functionality with respect to components. Props get passed to the component similar to function parameters whereas the state is managed within the component similar to variables declared within a function.</p>
<h3 id="7-why-should-we-not-update-the-state-directly">7. Why should we not update the state directly?</h3>
<p>If you try to update the state directly then it won't re-render the component.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Wrong</span>
<span class="hljs-built_in">this</span>.state.message = <span class="hljs-string">'Hello world'</span>
</code></pre>
<p>Instead, usesetState() method. It schedules an update to a component's state object. When the state changes, the component responds by re-rendering.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//Correct</span>
<span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Hello World'</span> })
</code></pre>
<p>Note: You can directly assign to the state object either in theconstructor or using the latest javascript's class field declaration syntax.</p>
<h3 id="8-what-is-the-purpose-of-the-callback-function-as-an-argument-of-setstate">8. What is the purpose of the callback function as an argument of setState()?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636962738118-image.png" alt="react setState" /></p>
<p>The callback function is invoked when setState finishes and the component gets rendered. Since setState()is asynchronous the callback function is used for any post action.
<strong><em>Note:</em></strong> It is recommended to use the lifecycle method rather than this callback function.</p>
<pre><code class="lang-javascript">setState({ <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span> }, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'The name has updated and component re-rendered'</span>))
</code></pre>
<h3 id="9-what-is-the-difference-between-html-and-react-event-handling">9. What is the difference between HTML and React event handling?</h3>
<p>Below are some of the main differences between HTML and React event handling:</p>
<ol>
<li>In HTML, the event name usually represented in lowercase as a convention:<pre><code class="lang-javascript">&lt;button onClick={activateLasers}&gt;
</code></pre>
Whereas in React it follows camelCase</li>
</ol>
<pre><code class="lang-javascript">&lt;button onClick={activateLasers}&gt;
</code></pre>
<ol>
<li>In HTML, you can return false to prevent the default behavior.</li>
</ol>
<pre><code class="lang-javascript">&lt;a href=<span class="hljs-string">'#'</span> onclick=<span class="hljs-string">'console.log("The link was clicked."); return false;'</span> /&gt;
</code></pre>
<p>Whereas in React you must call preventDefault() explicitly:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params">event</span>) </span>{
  event.preventDefault()
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'The link was clicked.'</span>)}
</code></pre>
<ol>
<li>In HTML, you need to invoke the function by appending () Whereas in react you should not append () with the function name. (refer to "activateLasers" function in the first point for example)</li>
</ol>
<h3 id="10-how-to-bind-methods-or-event-handlers-in-jsx-callbacks">10. How to bind methods or event handlers in JSX callbacks?</h3>
<p>There are 3 possible ways to achieve this:</p>
<p>Binding in Constructor: In JavaScript classes, the methods are not bound by default. The same thing applies to React event handlers defined as class methods. Normally we bind them in the constructor.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-built_in">this</span>.handleClick = <span class="hljs-built_in">this</span>.handleClick.bind(<span class="hljs-built_in">this</span>);
  }
  handleClick() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Click happened'</span>);
  }
  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleClick}</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
  }
}
</code></pre>
<p>Public class fields syntax: If you don't like to use the bind approach then public class fields syntax can be used to correctly bind callbacks.</p>
<pre><code class="lang-javascript">handleClick = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'this is:'</span>, <span class="hljs-built_in">this</span>)
}

&lt;button onClick={<span class="hljs-built_in">this</span>.handleClick}&gt;
  {<span class="hljs-string">'Click me'</span>}
&lt;/button&gt;
</code></pre>
<p>Arrow functions in callbacks: You can use arrow functions directly in the callbacks.</p>
<pre><code class="lang-javascript">handleClick() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Click happened'</span>);
}
render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> this.handleClick()}&gt;Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p><strong><em>Note:</em></strong> If the callback is passed as a prop to child components, those components might do an extra re-rendering. In those cases, it is preferred to go with the .bind() or public class fields syntax approach considering performance.</p>
<h3 id="11-what-are-synthetic-events-in-react">11. What are synthetic events in React?</h3>
<p>SyntheticEvent is a cross-browser wrapper around the browser's native event. Its API is the same as the browser's native event, including stopPropagation() and preventDefault(), except the events work identically across all browsers.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1636963964365-image.png" alt="Synthetic events" /></p>
<h3 id="12-what-is-the-key-prop-and-what-is-the-benefit-of-using-it-in-arrays-of-elements">12. What is the "key" prop and what is the benefit of using it in arrays of elements?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636964056467-image.png" alt="Keys" /></p>
<p>A key is a special string attribute you should include when creating arrays of elements.Keyprop helps React identify which items have changed, are added, or are removed.Most often we use the ID from our data askey:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> todoItems = todos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>
    {todo.text}
  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
)
</code></pre>
<p>When you don't have stable IDs for rendered items, you may use the itemindex as a key as a last resort:</p>
<h3 id="13-what-is-lifting-state-up-in-react">13. What is Lifting State Up in React?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636976926667-image.png" alt="Lifting state" /></p>
<p>When several components need to share the same changing data then it is recommended to lift the shared state up to their closest common ancestor. That means if two child components share the same data from its parent, then move the state to parent instead of maintaining local state in both of the child components.</p>
<h3 id="14-what-are-the-different-phases-of-the-component-lifecycle">14. What are the different phases of the component lifecycle?</h3>
<p>The component lifecycle has three distinct lifecycle phases:</p>
<ul>
<li><p>Mounting: The component is ready to mount in the browser DOM. This phase covers initialization from constructor(), getDerivedStateFromProps(), render(), and componentDidMount() lifecycle methods.</p>
</li>
<li><p>Updating: In this phase, the component gets updated in two ways, sending the new props and updating the state either from setState() or forceUpdate(). This phase covers getDerivedStateFromProps(), shouldComponentUpdate(), render(), getSnapshotBeforeUpdate() and componentDidUpdate() lifecycle methods.</p>
</li>
<li><p>Unmounting: In this last phase, the component is not needed and gets unmounted from the browser DOM. This phase includes the componentWillUnmount() lifecycle method.</p>
</li>
</ul>
<p>It's worth mentioning that React internally has a concept of phases when applying changes to the DOM. They are separated as follows:</p>
<ul>
<li><p>Render The component will render without any side effects. This applies for Pure components and in this phase, React can pause, abort, or restart the render.</p>
</li>
<li><p>Pre-commit Before the component actually applies the changes to the DOM, there is a moment that allows React to read from the DOM through the getSnapshotBeforeUpdate().</p>
</li>
<li><p>Commit React works with the DOM and executes the final lifecycles respectively componentDidMount() for mounting, componentDidUpdate() for updating, and componentWillUnmount() for unmounting.</p>
</li>
</ul>
<h3 id="15-what-are-portals-in-react">15. What are portals in React?</h3>
<p>Portal is a recommended way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.</p>
<pre><code class="lang-javascript">ReactDOM.createPortal(child, container)
</code></pre>
<p>The first argument is any render-able React child, such as an element, string, or fragment. The second argument is a DOM element.
<img src="https://aviyel.com/assets/uploads/files/1636977307288-image.png" alt="React portals" /></p>
<h3 id="16-what-are-stateless-components">16. What are stateless components?</h3>
<p>If the behaviour is independent of its state then it can be a stateless component. You can use either a function or a class for creating stateless components. But unless you need to use a lifecycle hook in your components, you should go for function components. There are a lot of benefits if you decide to use function components here; they are easy to write, understand, and test, a little faster, and you can avoid this keyword altogether.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1636977822024-image.png" alt="stateless components" /></p>
<h3 id="17-what-will-happen-if-you-use-props-in-the-initial-state">17. What will happen if you use props in the initial state?</h3>
<p>If the props on the component are changed without the component being refreshed, the new prop value will never be displayed because the constructor function will never update the current state of the component. The initialization of state from props only runs when the component is first created.The below component won't display the updated input value:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props)
    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">records</span>: [],
      <span class="hljs-attr">inputValue</span>: <span class="hljs-built_in">this</span>.props.inputValue
    };
  }
  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{this.state.inputValue}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  }
}
</code></pre>
<p>Using props inside the render method will update the value:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props)

    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">record</span>: []
    }
  }

  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{this.props.inputValue}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  }
}
</code></pre>
<h2 id="react-router">React Router</h2>
<h3 id="18-what-is-the-purpose-of-push-and-replace-methods-of-history">18. What is the purpose of push() and replace() methods of history?</h3>
<p>A history instance has two methods for navigation purposes.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1636980537374-image.png" alt="Navigation purpose" /></p>
<p>If you think of the history as an array of visited locations, push() will add a new location to the array and replace() will replace the current location in the array with the new one.</p>
<h3 id="19-how-do-you-programmatically-navigate-using-react-router">19. How do you programmatically navigate using React Router ?</h3>
<p>There are three different ways to achieve programmatic routing/navigation within components.</p>
<p>Using the withRouter() higher-order function:The withRouter() higher-order function will inject the history object as a prop of the component. This object provides push() and replace() methods to avoid the usage of context.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span> <span class="hljs-comment">// this also works with 'react-router-native'</span>

<span class="hljs-keyword">const</span> Button = withRouter(<span class="hljs-function">(<span class="hljs-params">{ history }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
    <span class="hljs-attr">type</span>=<span class="hljs-string">'button'</span>
    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { history.push('/new-location') }}
  &gt;
    {'Click Me!'}
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
))
</code></pre>
<p>Using  component and render props pattern:The  component passes the same props as withRouter(), so you will be able to access the history methods through the history prop.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>

<span class="hljs-keyword">const</span> Button = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">render</span>=<span class="hljs-string">{({</span> <span class="hljs-attr">history</span> }) =&gt;</span> (
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">'button'</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> { history.push('/new-location') }}
    &gt;
      {'Click Me!'}
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  )} /&gt;</span>
)
</code></pre>
<p>Using context:This option is not recommended and is treated as an unstable API.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">props, context</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
    <span class="hljs-attr">type</span>=<span class="hljs-string">'button'</span>
    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
      context.history.push('/new-location')
    }} &gt;
    {'Click Me!'}
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
)
Button.contextTypes = {
  <span class="hljs-attr">history</span>: React.PropTypes.shape({
    <span class="hljs-attr">push</span>: React.PropTypes.func.isRequired
  })
}
</code></pre>
<h3 id="20-how-to-get-query-parameters-in-react-router-v4">20. How to get query parameters in React Router v4?</h3>
<p>The ability to parse query strings was taken out of React Router v4 because there have been user requests over the years to support different implementations. So the decision has been given to users to choose the implementation they like. The recommended approach is to use the query strings library.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> queryString = <span class="hljs-built_in">require</span>(<span class="hljs-string">'query-string'</span>);
<span class="hljs-keyword">const</span> parsed = queryString.parse(props.location.search);
</code></pre>
<p>You can also use URLSearchParams if you want something native:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> params = <span class="hljs-keyword">new</span> URLSearchParams(props.location.search)
<span class="hljs-keyword">const</span> foo = params.get(<span class="hljs-string">'name'</span>)
</code></pre>
<p>You should use apply fill for IE11.</p>
<h2 id="react-redux">React Redux</h2>
<h3 id="21-what-are-redux-selectors-and-why-use-them">21. What are Redux selectors and why use them?</h3>
<p>Selectorsare functions that take the Redux state as an argument and return some data to pass to the component. For example, to get user details from the state:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getUserData = <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.user.data
</code></pre>
<p>These selectors have two main benefits,</p>
<p>The selector can compute derived data, allowing Redux to store the minimal possible state</p>
<p>The selector is not recomputed unless one of its arguments changes</p>
<h3 id="22-what-are-the-different-ways-to-write-mapdispatchtoprops">22. What are the different ways to write mapDispatchToProps()?</h3>
<p>There are a few ways of binding action creatorsto dispatch() in mapDispatchToProps().Below are the possible options:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mapDispatchToProps = <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> ({
 <span class="hljs-attr">action</span>: <span class="hljs-function">() =&gt;</span> dispatch(action())
})
<span class="hljs-keyword">const</span> mapDispatchToProps = <span class="hljs-function">(<span class="hljs-params">dispatch</span>) =&gt;</span> ({
 <span class="hljs-attr">action</span>: bindActionCreators(actioimport { ADD_TODO } <span class="hljs-keyword">from</span> <span class="hljs-string">'./actionTypes'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> (state = [], action) =&gt; {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> ADD_TODO:
      <span class="hljs-keyword">return</span> [
        ...state,
        {
          <span class="hljs-attr">text</span>: action.text,
          <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
        }
      ];
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state
  }
}
n, dispatch)
})
<span class="hljs-keyword">const</span> mapDispatchToProps = { action }
</code></pre>
<p>The third option is just a shorthand for the first one.</p>
<h3 id="23-what-is-the-difference-between-component-and-container-in-react-redux">23. What is the difference between component and container in React Redux?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636981323400-image.png" alt="component vs container" /></p>
<p>The component is a class or function component that describes the presentational part of your application.The container is an informal term for a component that is connected to a Redux store. Containerssubscribe to Redux state updates and dispatch actions, and they usually don't render DOM elements; they delegate rendering to presentational child components.</p>
<h3 id="24-what-is-the-mental-model-of-redux-saga">24. What is the mental model of redux-saga?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636981376214-image.png" alt="redux saga" /></p>
<p>Saga is like a separate thread in your application, that's solely responsible for side effects. redux-saga is a redux middleware, which means this thread can be started, paused and cancelled from the main application with normal Redux actions, it has access to the full Redux application state and it can dispatch Redux actions as well.</p>
<h3 id="25-what-are-the-differences-between-call-and-put-in-redux-saga">25. What are the differences between call() and put() in redux-saga?</h3>
<p>Both call() and put() are effect creator functions. call() function is used to create effect description, which instructs middleware to call the promise. put() function creates an effect, which instructs middleware to dispatch an action to the store.Let's take the example of how these effects work for fetching particular user data.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">fetchUserSaga</span>(<span class="hljs-params">action</span>) </span>{
  <span class="hljs-comment">// `call` function accepts rest arguments, which will be passed to `api.fetchUser` function.</span>
  <span class="hljs-comment">// Instructing middleware to call promise, it resolved value will be assigned to `userData` variable</span>
  <span class="hljs-keyword">const</span> userData = <span class="hljs-keyword">yield</span> call(api.fetchUser, action.userId)

  <span class="hljs-comment">// Instructing middleware to dispatch corresponding action.</span>
  <span class="hljs-keyword">yield</span> put({
    <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_USER_SUCCESS'</span>,
    userData
  })
}
</code></pre>
<h3 id="26-what-is-redux-thunk">26. What is Redux Thunk?</h3>
<p><img src="https://aviyel.com/assets/uploads/files/1636981476294-image.png" alt="Redux Thunk" /></p>
<p>Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of action or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch() and getState() as parameters.</p>
<h3 id="27-what-are-redux-selectors-and-why-use-them">27. What are Redux selectors and why use them?</h3>
<p>Selectors are functions that take the Redux state as an argument and return some data to pass to the component.For example, to get user details from the state:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getUserData = <span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.user.data
</code></pre>
<p>These selectors have two main benefits,</p>
<p>The selector can compute derived data, allowing Redux to store the minimal possible state</p>
<p>The selector is not recomputed unless one of its arguments changes</p>
<h3 id="28-what-is-a-diffing-algorithm">28. What is a diffing algorithm?</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4ig2favqumd6dk334d2.png" alt="Diffing Algorithm" /></p>
<p>React needs to use algorithms to find out how to efficiently update the UI to match the most recent tree. The diffing algorithm is generating the minimum number of operations to transform one tree into another. However, the algorithms have a complexity in the order of O(n3) where n is the number of elements in the tree.In this case, for displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:</p>
<ul>
<li>Two elements of different types will produce different trees.</li>
<li>The developer can hint at which child elements may be stable across different renders with a key prop.</li>
</ul>
<h3 id="29-is-it-prop-must-be-named-as-render-for-render-props">29. Is it prop must be named as render for render props?</h3>
<p>Even though the pattern named render props, you don’t have to use a prop named render to use this pattern. i.e, Any prop that is a function that a component uses to know what to render is technically a “render prop”. Lets take an example with the children prop for render props,</p>
<pre><code class="lang-javascript">&lt;Mouse&gt;  
{<span class="hljs-function"><span class="hljs-params">mouse</span> =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>The mouse position is {mouse.x}, {mouse.y}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
  )}&lt;/Mouse&gt;children={<span class="hljs-function"><span class="hljs-params">mouse</span> =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>The mouse position is {mouse.x}, {mouse.y}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
)}/&gt;
</code></pre>
<p>Actually children prop doesn’t need to be named in the list of “attributes” in JSX element. Instead, you can keep it directly inside element,</p>
<pre><code class="lang-javascript">&lt;&lt;Mouse&gt;  
{<span class="hljs-function"><span class="hljs-params">mouse</span> =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>The mouse position is {mouse.x}, {mouse.y}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
  )}&lt;/Mouse&gt;
</code></pre>
<p>While using this above technique(without any name), explicitly state that children should be a function in your propTypes.</p>
<pre><code class="lang-javascript">Mouse.propTypes = {
  <span class="hljs-attr">children</span>: PropTypes.func.isRequired
};
</code></pre>
<h3 id="30-what-are-the-problems-of-using-render-props-with-pure-components">30. What are the problems of using render props with pure components?</h3>
<p>If you create a function inside a render method, it negates the purpose of the pure component. Because the shallow prop comparison will always return false for new props, and each render in this case will generate a new value for the render prop. You can solve this issue by defining the render function as an instance method.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35f4mhoghz9ch1wz56ej.png" alt="Image description" /></p>
<h3 id="31-how-do-you-create-hoc-using-render-props">31. How do you create HOC using render props?</h3>
<p>You can implement most higher-order components (HOC) using a regular component with a render prop. For example, if you would prefer to have a with Mouse HOC instead of a component, you could easily create one using a regular with a render prop.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withMouse</span>(<span class="hljs-params">Component</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
    render() {
      <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Mouse</span> <span class="hljs-attr">render</span>=<span class="hljs-string">{mouse</span> =&gt;</span> (
          <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...this.props</span>} <span class="hljs-attr">mouse</span>=<span class="hljs-string">{mouse}</span> /&gt;</span>
        )}/&gt;</span>
      );
    }
  }
}
</code></pre>
<p>This way to render props gives the flexibility of using either pattern.</p>
<h3 id="32-what-is-windowing-technique">32. What is windowing technique?</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybuaah65yl84aje1hafk.png" alt="Image description" /></p>
<p>Windowing is a technique that only renders a small subset of your rows at any given time, and can dramatically reduce the time it takes to re-render the components as well as the number of DOM nodes created. If your application renders long lists of data then this technique is recommended. Both react-window and react-virtualized are popular windowing libraries which provide several reusable components for displaying lists, grids, and tabular data.</p>
<h3 id="33-what-is-the-typical-use-case-of-portals">33. What is the typical use case of portals?</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmkbak3b7vcajljx88lv.png" alt="Image description" /></p>
<p>React portals are very useful when a parent component has overflow: hidden or has properties that affect the stacking context(z-index,position,opacity etc styles) and you need to visually “break out” of its container.
For example, dialogs, global message notifications, hovercards, and tooltips.</p>
<h3 id="34-how-do-you-set-the-default-value-for-an-uncontrolled-component">34. How do you set the default value for an uncontrolled component?</h3>
<p>In React, the value attribute on form elements will override the value in the DOM. With an uncontrolled component, you might want React to specify the initial value, but leave subsequent updates uncontrolled. To handle this case, you can specify a defaultValue attribute instead of value.</p>
<pre><code class="lang-javascript">render() {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{this.handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        User Name:
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">"John"</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.input}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>The same applies for select and text Area inputs. But you need to use default Checked for checkbox and radio inputs.</p>
<hr />
<p>We have created a completely free eBook for you to download in the link below because we are unable to add all 300+ complete lists of questions due to character limitations.</p>
<hr />
<h2 id="download-for-free-herehttpsbitly300-plus-react-interview-questions">Download for free <a target="_blank" href="https://bit.ly/300-plus-react-interview-questions">here</a></h2>
<hr />
<p>This eBook will provide detailed instructions for anyone wishing to practice and improve their react.js skills. I urge that you properly read everything ahead of time and practice and sharpen your reaction skills. This is the most complete React JS interview questions book available. It has a lot of essential and often asked React JS interview questions and answers. Freshers, seasoned professionals, senior developers, and testers will benefit from a wide range of questions that cover not only the basics of React JS but also the most advanced questions. Cheers!! Happy coding and Best of Luck !!</p>
<p>Join us on our <a target="_blank" href="https://bit.ly/aviyel-discord">Discord</a> community to be a part of the React Study Circle !!</p>
]]></content:encoded></item><item><title><![CDATA[Web 3.0: Fusion of semantic web and Web 2.0]]></title><description><![CDATA[World Wide Web has greatly facilitated access to digitally stored data. Content on the World Wide Web, on the other hand, has only been machine-readable, not fully machine-understandable. Because most information on the World Wide Web is given in nat...]]></description><link>https://pramitmarattha.com.np/web-30-fusion-of-semantic-web-and-web-20</link><guid isPermaLink="true">https://pramitmarattha.com.np/web-30-fusion-of-semantic-web-and-web-20</guid><category><![CDATA[web]]></category><category><![CDATA[Web3]]></category><category><![CDATA[http]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Mon, 11 Oct 2021 04:56:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633927373319/uKHdzhPO7.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>World Wide Web has greatly facilitated access to digitally stored data. Content on the World Wide Web, on the other hand, has only been machine-readable, not fully machine-understandable. Because most information on the World Wide Web is given in natural language, the available documents can only be comprehended entirely by humans. The Semantic Web is built on the content-oriented description of digital documents using defined vocabularies to give machine-readable semantics. As a result, the Web of Links is transformed into a Web of Semantic Web. The classic Web 1.0 experienced an angular shift into Web 2.0, concentrating on categorization, intellectual capacity, and collective wisdom. Only the combined strength of semantic web technologies and widespread user participation will be leading to Web 3.0.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633067967881-1.png" alt="web3" /></p>
<p>The evolving semantic web cannot be grown and broadened to the degree required for a complete transformation of the current web without Web 2.0 technologies. On the other hand, without the addition of machine-understandable content descriptions based on semantic web technologies, current Web 2.0 technologies cannot be leveraged for automatic service composition as well. The ultimate global knowledge infrastructure cannot be fully automated; instead, it requires collective and widespread human participation based on open semantic platforms as well as standards.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633068023086-image.png" alt="progress of web 3" /></p>
<h2 id="beginning-of-the-web-20-era">Beginning of the Web 2.0 era.</h2>
<p>Web 2.0 denotes a fundamental change in the advancement of the internet: Web 1.0, also known as the Web of business and Companies, has given way to Web 2.0, known as the Web of individuals and People. This shift has not resulted in the introduction of new technologies, but it has significantly altered the user's role and value. Tim O'Reilly and Dale Dougherty of O'Reilly Media coined the term Web 2.0 to describe new emerging web applications and trends. Web 2.0, according to O'Reilly, is comprised of the following concepts:</p>
<ul>
<li><strong>Web as a platform:</strong> The web and all of its connected devices are regarded as a single global platform of reusable services and data on which to build using open standards.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068256488-image.png" alt="web as platform" /></p>
<ul>
<li><strong>Collective wisdom:</strong> A Tradition of Involvement emerges from the establishment of open systems that support and enable collaborative content production based on the notion of "having faith rather than having control". The observation is that a large number of users provides a great amount of knowledge, but that same large number of users also prevents misuse of services and removes incorrect content. Wikipedia is an excellent example of harnessing people's collective intelligence. It is a free Internet-based encyclopedia that was founded in 2001 and operates under an open-source management model. Wikipedia's open-source production model exemplifies Web 2.0, a socially progressive environment in which the web of social software entangles users in both their physical and virtual workplaces. The Wikipedia community is founded on a set of standard principles. Neutrality is an important principle. Another factor is the belief that contributors are acting in a sincere and deliberate manner. Readers can correct perceived errors, and disagreements over facts and possible bias are resolved through contributor discussions.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068284570-image-resized.png" alt="collective wisdom" /></p>
<ul>
<li><strong>Open source and service operations:</strong> In the Web 2.0 era, the software is delivered as a service rather than a product. The core competency of the companies involved in the daily operation of their services, not the algorithms used. The dynamic nature of the services necessitates continual, cost-effective transformation through the use of an open source development style. Many of the services have been in the “continual beta” phase for many years, with new features being introduced on a regular basis. Successful Web 2.0 businesses/companies are experts and experienced at tracking user activity in real-time to determine which new features are being currently used, how they are being used, and how they should be adjusted and adapted accordingly.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068305285-image.png" alt="open source" /></p>
<ul>
<li><strong>Fully data-driven:</strong> Databases are at the core of Web 2.0 processes, where the data itself is far more essential than the application or interface that utilizes it. The race to own certain classes of core data, such as location, identity, product identifying information, and namespaces, is on in the market. Moreover, a critical mass of data can be attained through user aggregation, and the gathered information is then turned into a system service.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068325752-image.png" alt="database" /></p>
<ul>
<li><strong>Beyond Personal Computers:</strong> Web 2.0 systems are distinguished by the fact that they are no longer restricted to the Desktop / PC platform. This is not new in terms of web applications, but Web 2.0 apps provide a more complete achievement of the web's full potential as a platform, embracing not only the world of interconnected PCs but also mobile phones and various portable / wearables gadgets as well as devices.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068342468-image.png" alt="Portable Gadgets" /></p>
<ul>
<li><strong>lightweight programming models:</strong> The easy connecting, expansion and mixing of data using simple Application programming Interfaces enable the construction of new, loosely connected web services every single day, as the syndication of data, not the piling of its utilization, has been recognized as a driving force in the market. As a result, many Web 2.0 services innovate by putting together components in unique and productive ways.</li>
</ul>
<ul>
<li><strong>Extensive user experience:</strong> Web applications currently offer extensive user interfaces and interactions with a server that were previously only available to high-profile consumers. Standards-based display and interaction, as well as asynchronous data retrieval with JavaScript linking everything together, are key components of the browser to achieve this behavior.</li>
</ul>
<p><img src="https://aviyel.com/assets/uploads/files/1633068365077-image.png" alt="User experience" /></p>
<p><strong>Web 2.0 is certainly not a new technology in general. It's a brand-new approach to working with data and including people in the process.</strong></p>
<h2 id="the-inception-of-semantic-web">The inception of “Semantic web.”</h2>
<p>“The Semantic Web is not a distinct Web, but an extension of the web 1.0 and web 2.0, in which information is given well-defined meaning, better-enabling machines and people to work together,” Tim Berners-Lee, Jim Hendler, and Ora Lassila wrote in a Scientific American article in 2001. To accomplish so, we'll need data about data, often known as metadata, which can express meaning and be shared among computers. Machines can utilize metadata to consume and produce data on the web if it is stored in a standardized format. Service agents may use this data to explore, analyze, integrate, organize, and reorganize it in new and innovative ways to help us solve problems, plan events, or simply schedule our leisure time. Markup languages with a formalized syntax and semantics provide a defined notion for defining digital resources in the form of a schema, which are the key technology elements for the Semantic Web. Ontologies can be shared and distributed globally using semantic markup languages like Web Ontology Language.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633069459043-image.png" alt="webpage annotation" /></p>
<p>Tim Berners Lee's Web layer cake is made up of these three levels of web annotations. It organizes a variety of new standards and concepts into a Semantic Web hierarchy. Unicode and Uniform Resource Identifier are the foundation standards for identifying resources in general on the lowest layer. On the second layer, we have XML(extensive markup language), which is utilized to specify the interchange format of underlying data models that are strictly syntactic and structural. On the third tier, the Resource Description Framework and its schema comprise the most fundamental and widely used triple-based Semantic Web representation language. Ontology vocabularies make up the next tier. The Semantic Web's next layer adds functionality: systems may draw conclusions and make judgments using logic and rules. However, the proof is required to depend on these conclusions, which is the sixth layer of the Semantic web stack. Finally, there is the issue of trust. The Semantic Web does not claim that every assertion found on the internet is correct. However, all assertions on the Internet are made in context, and each application must use this context to assess its credibility.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633068525409-image.png" alt="semantic web stack" /></p>
<p>Machine learning, data mining, and text mining approaches minimize the manual labor of building and maintaining ontologies, while the layer of logic and rules can improve search algorithms. Ontologies can be developed, edited, evaluated, merged, and validated using a number of software tools. The Semantic Web can help with the massive problem of information overload.</p>
<h2 id="web-30-hybrid-of-semantic-web-and-web-20">Web 3.0: Hybrid of semantic web and Web 2.0</h2>
<p>Web 3.0 is an extension of Web 2.0, which can be thought of as a service-oriented Web that encourages and enables user cooperation and communication. Although there is no consensus on the particular characteristics that define Web 3.0, many researchers agree that semantic technologies and customization techniques play a significant role in it. Web 3.0 can thus be considered as a semantic and personalized variant of Web 2.0 from this standpoint.</p>
<p>Web 3.0's objective is to bring together the concepts of Web 2.0 and the upcoming Semantic Web technologies in a multidisciplinary setting. The lightweight and community-based technologies of Web 2.0 must be employed to lower the enormous costs of constructing an entire Semantic Web so that every web user can contribute a piece of meaning to the growing Semantic Web. The desire to provide a platform on which others can build, use, and combine apps signifies the direction in which Semantic Web applications should be permitted to progress. The widespread adoption of Web 2.0 and its evolution can catalyze the development of semantic technologies. The Semantic Web is currently being held back by its complexity and a lack of a network effect from a large community. The required semantic tagging, extracting, classifying, and organizing effort is time-consuming, and there aren't many easy solutions that satisfy consumers' self-interest and demonstrate the value of Semantic Web technologies right away.</p>
<p>Full article =&gt; https://aviyel.com/post/1018/web-3-0-fusion-of-semantic-web-and-web-2-0</p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item><item><title><![CDATA[What is the philosophy of Docz - an open source software documentation tool?]]></title><description><![CDATA[Software documentation is crucial for programmers. Its purpose is to aid software maintainers in comprehending a system and its processes. In practice, however, creating source code documentation is expensive, resulting in documentation that is frequ...]]></description><link>https://pramitmarattha.com.np/what-is-the-philosophy-of-docz-an-open-source-software-documentation-tool</link><guid isPermaLink="true">https://pramitmarattha.com.np/what-is-the-philosophy-of-docz-an-open-source-software-documentation-tool</guid><category><![CDATA[documentation]]></category><category><![CDATA[DOM]]></category><category><![CDATA[React]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Tue, 05 Oct 2021 12:42:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633437613106/2LGiO3CWg.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Software documentation is crucial for programmers. Its purpose is to aid software maintainers in comprehending a system and its processes. In practice, however, creating source code documentation is expensive, resulting in documentation that is frequently incomplete and of poor quality. Poor software documentation can quickly degrade the quality and usability of a software system. It is difficult to write documentation because it requires programmers to guide other programmers. This difficulty creates a barrier between the authors of documentation and the readers.</p>
<p>Understanding a given piece of code that was most likely written by someone else is a significant challenge in software development/maintenance. According to research (Source), the program comprehension process may account for more than 60% of the software maintenance effort. Design decisions taken in the past have a major effect on developers' work in developing long-term software products today. If the challenge is to modify the current program, the program must first be fully understood by the developers.</p>
<p>Documentation generation tools are appearing to assist authors in expediting the documentation process. The creators of these tools must understand what constitutes a good summary. They must also understand whether certain information is irrelevant or misleading in order to avoid including it. Several documentation tools are already available on the market like Docusaurus, SlimWiki, GitBook, MkDocs, ZocDoc, and Docz.</p>
<p>Docz is one among them and might be the best possible tool since it is entirely open source and has around 21k stars and 1400 forks on their Github. Docz is built using Gatsby underneath the hood, making it an incredibly fast modern doc generator and one of the most advanced tools of the new frontend era. This article focuses primarily on what Docz is and the philosophy that underpins it.</p>
<p>‌</p>
<h1 id="a-guide-to-successful-code-documentation">A guide to successful code documentation</h1>
<p><img src="https://aviyel.com/assets/uploads/files/1633344046569-philosophy-of-docz.png" alt /></p>
<h1 id="transforming-a-concept-into-a-reality">Transforming a concept into a reality</h1>
<p>It's easy to have a big idea, but illustrating and putting it into words requires a lot of thought distillation. The code's design is improved by documenting it. The author can think about the API and design decisions more formally after writing them down. It also allows other developers to add code that follows the author's intentions as a positive side effect.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633344126015-philosophy-of-docz-1.png" alt /></p>
<h1 id="what-to-write">What to write?</h1>
<p>Firstly, you must ask yourself for whom to write. You usually have to appeal to either users or developers. Users are just people who want to use the code and aren’t concerned about how it works, whereas developers like to contribute to the code again.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633344175370-philosophy-of-docz-2.png" alt /></p>
<h1 id="which-project-license-should-you-pick">Which project license should you pick?</h1>
<p>There are numerous licenses for free/libre open source software, significantly used for a single software application. Since the beginning of January 2011, 96 percent of all projects have had the top 20 most commonly used licenses. With over 60 percent of all the projects using one of the GPL licenses, the GNU General Public License (GPL) family of licenses remains the most used license group for free/libre open source software projects. This sluggish distribution of license use has led to a community call for standardization of a limited number of free/libre open source software licenses that are known and recognized in order either to guarantee a clear understanding of mutual obligations when mixing code for various projects and to streamline the process of managing contribution. The decision to use an open source license for a project's code base is not straightforward and is influenced by several factors. In general, when reusing code from other projects, license compatibility is the most important factor in selecting a perfect license for the project.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633344238579-philosophy-of-docz-3.png" alt /></p>
<h1 id="reusability-of-code">Reusability of code</h1>
<p>Do not Repeat Yourself (DRY) software development principle states that duplication in logic should be eliminated through abstraction, while duplication in process should be eliminated through automation. It's a complete waste of time to duplicate tasks again and again. Adding completely unnecessary code to a codebase increases the amount of work needed to extend and maintain the software in the future. So good programmers make reusable code components and try not to repeat themselves in their code. As a result, everything should be very well documented so that other developers can jump right into the codebase and start using that code component without any hassle or difficulty.</p>
<h1 id="reference-manual-for-reporting-project-issues">Reference manual for reporting project issues</h1>
<p>The scope of a project can be determined with the help of documentation. Some people might find the source code compelling. They might be interested in reporting any issues in the code they find. As a result, documenting every step-by-step guide for reporting issues makes it a lot easier for anyone who wants to help with the project.</p>
<h1 id="meaningful-readme">Meaningful Readme</h1>
<p>README file is a document that provides users with a detailed description of a project that you've uploaded to your repository. An excellent README can help the project stand out among others. It should be on par with the project. It is the first file a person sees when they come across your project, so it should be very concise but thorough. README also helps to assist users and developers in focusing on what the project must deliver and how it must be delivered.</p>
<h1 id="setup-guide">Setup guide</h1>
<p>Users need to know how to get your code and run it once they've decided whether or not they want to use it. For the most part, your setup guide should be thoroughly documented and should be a couple of lines long. If necessary, a page with more information and details should be linked.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633344382780-setup-guide.png" alt /></p>
<h1 id="frequently-asked-questionsfaq">Frequently Asked Questions(FAQ)</h1>
<p>Every day, a large number of people face the same common problems. If this occurs frequently, you should probably update your documentation or code to address the problem. There will, however, always be questions about your project, as well as things that cannot be changed. As a result, documenting and keeping track of the entire process is critical. In general, projects evolve daily, so FAQs quickly become obsolete, but when done well, they can be a very useful resource.</p>
<h1 id="idea-behind-docz-the-powerful-software-documentation-tool">Idea behind Docz: The powerful software documentation tool</h1>
<p>Maintaining the documentation manually takes a lot of time and effort, which slows down the process of releasing a new version of the product itself. Docz is crafted on the following lines- to ease the pressure from coders so they can devote themselves entirely to innovation rather than spending time in handling complex configuration. Docz’s SEO friendly tools support developers in curating an optimized documentation that can be further utilized by aspiring innovators.</p>
<p>‌</p>
<p>In a world of commercial and closed source documentation software, Docz stands high above the ground. The open source technology enables Docz to share their product with communities facing resource crunch but committed to foster innovation. It allows users to quickly create live-reloading, production-ready documentation sites with MDX and personal customisation. The creators of Docz wanted it to be freely available and inspire developers into monetising and crafting faster documentation. That marks the philosophy of Docz- free availability and an outreach to communities.</p>
<p>‌</p>
<p>Docz is entirely built with GatsbyJS. It is intended for extremely fast development and build times. It also makes extensive use of GatsbyJS's large ecosystem of plugins and tools. Building and running documentation with docz does not always necessarily require complex configuration settings. You can easily create beautiful, customizable sites with a single command. It is based on mdx, which allows you to import and use your own components inside Markdown-style files. Docz can also be customized with plugins, and it includes native TypeScript support for TSX components, as well as the ability to generate documentation directly from prop types and comments inside of the code.</p>
<p>GitHub - doczjs/docz: ✍ It has never been so easy to document your things!</p>
<p><img src="https://aviyel.com/assets/uploads/files/1633344465246-idea-behind-docz-resized.png" alt /></p>
<h1 id="what-makes-docz-the-best-documentation-software">What makes Docz the best documentation software?</h1>
<ul>
<li><p>Gatsby powered: Docz is entirely built using GatsbyJS. It's optimised for a lightning-fast development experience and speedy build times. This also allows you to leverage GatsbyJS's huge ecosystem of plugins and tools.</p>
</li>
<li><p>Easily Customizable: Docz is highly customizable to create and personalize your very own theme</p>
</li>
<li><p>Blazingly Fast: Docz supports hot reloading and automatic code-splitting right out of the box.</p>
</li>
<li><p>Based on MDX: Docz is based on mdx, which means it allows you to import and use your own components in Markdown-style files.</p>
</li>
<li><p>TypeScript Support: Docz includes native TypeScript support for TSX components, as well as the ability to generate documentation directly from prop types and comments inside the code itself.</p>
</li>
</ul>
<p><a target="_blank" href="https://aviyel.com/post/1033/what-is-the-philosophy-of-docz-an-open-source-software-documentation-tool">Click here for full article</a></p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Simplifying and Automating Mobile Security Testing through MobSF]]></title><description><![CDATA[In the last decade, mobile security technology has gained traction to counter cyber threats in the industry. Mobile technologies such as cell phones, tablets are heavily used to surf the web, run apps, read email, post to social media, conduct financ...]]></description><link>https://pramitmarattha.com.np/simplifying-and-automating-mobile-security-testing-through-mobsf</link><guid isPermaLink="true">https://pramitmarattha.com.np/simplifying-and-automating-mobile-security-testing-through-mobsf</guid><category><![CDATA[Security]]></category><category><![CDATA[Mobile apps]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[mobile]]></category><category><![CDATA[technology]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Thu, 09 Sep 2021 11:36:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1631186640498/hrt9RIUvt.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last decade, mobile security technology has gained traction to counter cyber threats in the industry. Mobile technologies such as cell phones, tablets are heavily used to surf the web, run apps, read email, post to social media, conduct financial &amp; banking transactions, etc. There has been a tremendous surge in the use of mobile devices for both personal and business uses. The advent of mobile devices and the proliferation of mobile applications have facilitated mobility on a large scale. Because of this, concerns have arisen about the issues of preserving security when traveling across the digital realm.</p>
<p>According to Statista’s report, there are 6.378 billion-plus mobile phone users in the globe- comprising 95% of the entire world's population.</p>
<p>With cases of frequent user privacy breaches, mobile device security continues to grow in importance. Although businesses are concerned about mobile security and data privacy, the use of applications from the internet causes serious problems in terms of addressing threats and vulnerabilities while securing a user's data privacy. Most software apps are built to do a certain activity and are aimed at a specific set of devices, such as smartphones and tablets. Mobile device data protection is a risky endeavor due to the various threats and vulnerabilities involved.</p>
<h2 id="difficulties-with-mobile-device-security">Difficulties with Mobile Device Security</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1631185661294/myRpy57HM.png" alt="image.png" /></p>
<p>The mobile market is growing as wireless technology advances and mobile device usage improves. The growth in the development and maintenance of secure identities for mobile devices has created a huge challenge for individuals, society, and businesses, particularly in mobile added-value services such as mobile banking, and mobile ticketing. The following are a few of the most notable difficulties with mobile devices as a result of threats and vulnerabilities.</p>
<h2 id="sensitive-data-and-information-leaks">Sensitive Data &amp; Information leaks</h2>
<p>When sensitive data and information such as password credentials, secret keys, access tokens, sensitive business logic, are defined/hardcoded into the application code, it opens the door for an attacker to discover this information by reverse engineering it. Once such information is in the hands of an attacker, the situation might become very chaotic.</p>
<h2 id="unguarded-data-storage">Unguarded Data Storage</h2>
<p>General non-encryption, caching of information that is not intended for long-term storage, and a lack of platform best practices can lead to exposure of sensitive information.</p>
<h2 id="weak-authentication-and-authorization">Weak Authentication and Authorization</h2>
<p>When it comes to security, weak authorization and authentication techniques that depend on device-identifiers such as the International Mobile Equipment Identity (IMEI)  and universally unique identifier (UUID) values are a perfect recipe for disaster.</p>
<h2 id="server-side-control">Server-Side Control</h2>
<p>On the backend side, failure to apply effective security measures like patches/updates &amp; secure configs can result in a massive data breach.</p>
<h2 id="brute-force-attack">Brute Force Attack</h2>
<p>There are several mobile applications today that use password-based authentication as single-factor authentication. Because of this, the proprietors of these programs don't enforce strong passwords or the protection of valuable credentials. User's credentials can be stolen, and automated brute force assaults can be launched against them.</p>
<h2 id="improper-session-handling">Improper Session Handling</h2>
<p>Session handling has been flagged as a security problem for web applications on mobile devices. When using internet apps on any platform, such as mobile devices or PCs, improper session handling creates risks. When executing financial transactions, sessions with long expiry durations create vulnerabilities. Such session hijacking on mobile devices can be traced back to poor session management.</p>
<h2 id="lack-of-transport-layer-protection">Lack of Transport Layer Protection</h2>
<p>In mobile applications, it is common to see no encryption for sent data. However, disregarding certificate validation issues or reverting to plain text communication after failures can put security in peril and have significant consequences such as data tampering and can even encourage man-in-the-middle attacks if they are not addressed immediately.</p>
<h2 id="client-side-injection">Client-Side Injection</h2>
<p>On mobile devices, malicious applications are executed via application or web browsing client-side injections. Client-side injections can take the form of HTML injections or SQL injections. It's possible for hackers to launch a text-based assault and take advantage of a targeted user. By using this method hackers can inject any data source, including resource-targeted files or software, into the system.</p>
<p><a target="_blank" href="https://aviyel.com/post/773/simplifying-and-automating-mobile-security-testing-through-mobsf">Click Here for full article</a></p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Begin with Chatwoot- an Open Source Platform for Customer Engagement]]></title><description><![CDATA[Today, many business organizations are facing flak from their competitors. Because of the tough competitive environment, businesses are constantly looking for different ways to craft new products. One viable and critical strategy is to focus on offer...]]></description><link>https://pramitmarattha.com.np/how-to-begin-with-chatwoot-an-open-source-platform-for-customer-engagement</link><guid isPermaLink="true">https://pramitmarattha.com.np/how-to-begin-with-chatwoot-an-open-source-platform-for-customer-engagement</guid><category><![CDATA[chatbot]]></category><category><![CDATA[services]]></category><category><![CDATA[Chat]]></category><category><![CDATA[realtime]]></category><category><![CDATA[realtime apps]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Mon, 06 Sep 2021 03:14:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1630897962972/ZUYhB7wYW.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, many business organizations are facing flak from their competitors. Because of the tough competitive environment, businesses are constantly looking for different ways to craft new products. One viable and critical strategy is to focus on offering high-quality customer support and services. Customer support and services guide businesses to succeed and can be a source of competitive advantage for companies. In addition to improving the relationship between the business and customers, good customer support &amp; service plays a key part in boosting customer loyalty for those specific businesses.</p>
<p>Nowadays, industrial manufacturers are also providing customer services. This allows them to broaden their activities and serve their customers better. Customers and businesses can both benefit from customer services. Many buyers base their final purchase decisions on the product's pricing, range, and degree of customer service.</p>
<p>Therefore, companies and businesses should make use of customer service tools to provide exceptional customer service. There are many tools that provide customer services like Chatify , Salesforce, Hubspot , Olark and Chatwoot.</p>
<h2 id="chatwoots-journey-2016-present">Chatwoot’s Journey: 2016-Present</h2>
<p>Chatwoot is a free open source live chat platform with enterprise-level functionality. It includes features like real-time reporting, live chats, automatic agent assignment, chatbots, shared inboxes, powerful APIs/webhooks, canned responses, conversations continuity, conversations labels, and much more features. Chatwoot is also quite simple to use. Its user-friendly dashboard allows business agents to focus only on supporting customers rather than figuring out how to use the platform.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1630897572959/SNQ65Dp6E.png" alt="image.png" /></p>
<p>Most companies already engage with users through their email, website, and social media handles. However, different mediums of communication can make the whole process chaotic. It is equally vital for companies to keep a track of their conversations with consumers. Chatwoot is a natural fit for this actual situation.</p>
<p>Chatwoot was created in 2016. However, it was revived in 2019’s Hacktoberfest after a sluggish start. Most users were surprised when Chatwoot became a popular project on Hacker News. It appears that a failed initiative has now been resurrected, with very outstanding and promising results.</p>
<h2 id="how-is-chatwoot-different">How is Chatwoot Different?</h2>
<p>Chatwoot provides a unified picture of conversations between different communication channels, such as email, websites, API, and social media platforms.</p>
<p>Some of the key main features of Chatwoot are:</p>
<ul>
<li><p>open source: Chatwoot is a free and completely open source live chat platform with enterprise-level functionality which unquestionably sets it apart from the crowd. Unlike other customer service software on the market, Chatwoot's open-source feature makes it even more powerful and versatile because anyone can download, change, and enhance the source code according to their own requirement and host it on their own personal server.</p>
</li>
<li><p>Mobile Application: Chatwoot also has its own mobile application available for both Android and iOS operating systems, allowing you to manage your customer conversations on the go.</p>
</li>
<li><p>Real-time reports: Reports are crucial and necessary tools for any business, no matter its size or industry. They allow tracking and analysis of the performance, overall health, identification of areas for development, and potential for growth.  Real-time reporting is included inside Chatwoot, so discussions, messages, and reaction times can be recorded and analyzed in real-time with ease.</p>
</li>
<li><p>Live chat: Customers enjoy live chat because it allows them to get immediate answers to their inquiries and concerns. Consumers can reach out to businesses directly via live chat. Sending an email to a support team is less convenient because you never know when you'll get a response from them. Customer satisfaction ratings for live chat tend to be higher than for other methods of support because of the speed and availability. Chatwoot live chat interface is simple and stylish, an ideal mix for potential clients. In addition, it is quite easy to use and retains a great appearance, alluring customers.**</p>
</li>
<li><p>Shared inboxes: Chatwoot helps enterprises communicate with customers and team members from a single location easily.</p>
</li>
<li><p>Private notes: Inter-team communication is available by using private notes in a chat. You can tag to convey important information, resolve issues and address concerns.</p>
</li>
<li><p>Powerful API &amp; webhooks: Information about what is happening in the account is available in real-time via Webhooks. Communication of various events between programs such as Slack &amp; GitHub can also be accomplished using webhooks. Right now, Chatwoot is directly integrated with Slack. It is possible to manage Slack discussions without ever having to enter into its dashboard.</p>
</li>
<li><p>Canned Responses: Typing the entire same response might be exhausting at times. Chatwoot accounts for this problem by providing prefabricated and pre-recorded short responses, thus enhancing user experience.</p>
</li>
<li><p>Chatbots: Chatbots joined the mainstream tech industry towards the dawn of the 21st Century. Online chat has been invaded and occupied by interactive technology, frequently paired with AI. Chatbots aren't only a component of virtual assistants; they're utilized by various businesses to advertise products, ideas, and services on websites, applications, and instant messaging systems. Chatwoot has its own chatbot feature with built-in integration with Rasa (open-source conversational AI) and Dialogflow(closed source conversational AI owned by google). Through Chatwoot, customers can delegate conversations to bots and communicate with actual human beings when necessary.</p>
</li>
<li><p>Multilingual support: Chatwoot currently supports more than 20 different languages.</p>
</li>
</ul>
<p><a target="_blank" href="https://aviyel.com/post/751/how-to-begin-with-chatwoot-an-open-source-platform-for-customer-engagement">Click Here for full article</a></p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Learn how to make a secure mobile application.]]></title><description><![CDATA[📜 About:
"14 Days of Mobile Security" is a social learning and accountability program for mobile developers to build a security-centric culture and to achieve the goal of creating secure mobile apps.
One of the most common mistakes made by new or yo...]]></description><link>https://pramitmarattha.com.np/learn-how-to-make-a-secure-mobile-application</link><guid isPermaLink="true">https://pramitmarattha.com.np/learn-how-to-make-a-secure-mobile-application</guid><category><![CDATA[Security]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Devops]]></category><category><![CDATA[challenge]]></category><category><![CDATA[newbie]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Sat, 04 Sep 2021 06:24:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1630733089339/tGExt-n6N.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="about">📜 About:</h2>
<p>"14 Days of Mobile Security" is a social learning and accountability program for mobile developers to build a security-centric culture and to achieve the goal of creating secure mobile apps.</p>
<p>One of the most common mistakes made by new or young mobile developers is a lack of knowledge or foundations in security development practice. They begin working on their 'development style' before learning security practices and methods. To assist you, we have developed a practical roadmap called "14 Days of Security," which is based on extensive research and the experience of mobile security developers working in large tech companies.</p>
<h2 id="so-what-are-you-going-to-get">🧮 So, what are you going to get?</h2>
<ul>
<li><p>Learn the fundamentals of mobile security from scratch.</p>
</li>
<li><p>Start to learn security practices even if you have never picked a book on security.</p>
</li>
<li><p>Master your mobile security foundations.</p>
</li>
<li><p>Create and learn through open source tools and frameworks along with videos and text tutorials.</p>
</li>
</ul>
<h2 id="win-exciting-prizes">💝 Win Exciting Prizes🎁</h2>
<ul>
<li>After completing the challenge, you will receive a free subscription to a premium course.</li>
<li>Obtain a completion certificate.</li>
<li>Submissions with more than 5 upvotes will receive the top peer badge of the day or week.</li>
<li>Anyone who earned 14 challenge completion badges and 5 top peer badges can request a 14-day mobile security challenge completion certificate from the Aviyel Team.</li>
</ul>
<h2 id="how-do-you-start">🏁 How do you start?</h2>
<ul>
<li><p>Sign-up for free and Text "Pledge" on the comment box of this article <a target="_blank" href="https://bit.ly/14DaysMobSec">14 days of mobile security</a></p>
</li>
<li><p>Dedicate 1 hr every day for the next 14 days to learn one mobile security.</p>
</li>
<li><p>Every day, set a goal of reading an article, developing a security tool to audit your app, or utilizing a security framework to encrypt your data-in-transit or data-in-storage. You can choose articles and tutorials from the content repository, or you can follow any article or tutorial on Mobile Security. We have also created a repository of mobile security concepts to search or research for the program to help you narrow your search.</p>
</li>
<li><p>After finishing the day's activities, you can choose a challenge from our Challenge repo. To complete the challenge, simply share a screenshot of your tutorial's results, GitHub code, a short post, and so on. This earns you a completion badge.</p>
</li>
<li><p>Any challenge submission that receives more than 5 upvotes will be awarded the top peer badge of the day or week.</p>
</li>
<li><p>Any participant who received 14 challenge completion badges with 5 top peer badges can apply for 14 days of mobile security challenge completion certificate from the Aviyel Team.</p>
</li>
<li><p>Top "Day X Submission" of the Day and Week will be selected and pinned 📍.</p>
</li>
</ul>
<h2 id="roadmap-content">🗺️ Roadmap Content</h2>
<p>To help you with this, we have created a practical roadmap, “14 days of Security,” based on a lot of research and the experience of mobile security developers working in big tech companies. This roadmap will give you a complete guideline to build a strong coding habit and to achieve your goal of creating a secure mobile app.</p>
<ul>
<li><p>Video </p>
</li>
<li><p>Blogs</p>
</li>
<li><p>Audio</p>
<p><a target="_blank" href="https://aviyel.com/post/401/roadmap-content">Here </a> are the list of the entire content.</p>
</li>
</ul>
<h2 id="roadmap-content-theme">🗺️ Roadmap Content Theme</h2>
<ul>
<li><p><a target="_blank" href="https://aviyel.com/post/431/end-to-end-encryption">End to End Encryption</a></p>
</li>
<li><p><a target="_blank" href="https://aviyel.com/post/332/secure-code-review-checklist">Code Quality Checklist</a></p>
</li>
<li><p><a target="_blank" href="https://aviyel.com/post/734/obfuscating">Obfuscating</a></p>
</li>
<li><p><a target="_blank" href="https://aviyel.com/post/735/encrypt-your-data">Encrypt your data</a></p>
</li>
<li><p><a target="_blank" href="https://aviyel.com/post/739/certificate-transparent">Certificate Transparent</a></p>
</li>
</ul>
<p>✨ Tweet / post your progress on  <a target="_blank" href="https://aviyel.com/discussions">Aviyel </a> by using hashtag #14DaysOfSec and the hashtag of the challenge in which you participate from this day forward for the next 14 days.</p>
]]></content:encoded></item><item><title><![CDATA[Future of Open Source in Quantum Computing: A Brief Analysis]]></title><description><![CDATA[Quantum Computing was the result of an absurd experiment by Schrödinger on his cat. Quantum computing is under development but has the potential to transform the computing industry. In less than a decade, quantum computing has progressed from a theor...]]></description><link>https://pramitmarattha.com.np/future-of-open-source-in-quantum-computing-a-brief-analysis</link><guid isPermaLink="true">https://pramitmarattha.com.np/future-of-open-source-in-quantum-computing-a-brief-analysis</guid><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Wed, 01 Sep 2021 16:23:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1630513442514/hDwVSx6ho.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Quantum Computing was the result of an absurd experiment by Schrödinger on his cat. Quantum computing is under development but has the potential to transform the computing industry. In less than a decade, quantum computing has progressed from a theoretical concept to solving fascinating puzzles.</p>
<p>Quantum computers are the successors of the historical classical computers. Quantum computers need users to express a quantum algorithm as a sequence of fundamental quantum logic gates, similar to punch cards or an assembler in a classical computer.</p>
<p><img src="https://aviyel.com/assets/uploads/files/1629378877699-image5-resized.png" />
Various organizations, private companies, governments, and universities worldwide successfully demonstrated a hardware execution of quantum computing. Numerous quantum computing projects have emerged in the last decade with an intense focus on platform integration of quantum computation.</p>
<p>Quantum computing can offer an aggressive boost to many issues considered inconceivable today. The field is dynamic and young, with software projects continuously pushing the boundary of human knowledge. However, the studies in quantum computing suffer from understaffing and a lack of scientists, programmers, and developers with skills relevant to this field. Other challenges that hamper further progress in quantum technology include:</p>
<ul>
<li><p>Unpredictable changes in the requirements.</p>
</li>
<li><p>Lack of software development experience.</p>
</li>
<li><p>A tight budget.</p>
</li>
</ul>
<h1 id="understanding-quantum-computing">Understanding Quantum Computing</h1>
<p>In 1980, physicist Paul Benioff proposed a quantum mechanical model of the Turing machine sparking the beginning of quantum computing. It is the processing of information using unique quantum states. By utilizing quantum phenomena such as "superposition" and "entanglement," these machines process faster information than classical or powerful supercomputers. In contrast to traditional computation, which involves manipulating binary digits (0s and 1s), quantum computers use the qubit as their fundamental unit. Unlike bits, a qubit can exist as a superposition of both 0s and 1s, revolving one way or another only when measured. A qubit can encode a state of a quantum mechanical object (example: polarization of a single photon).</p>
<p><img src="https://aviyel.com/assets/uploads/files/1629378911620-image4-resized.png" /></p>
<p>The field of quantum computing is rapidly evolving and changing. Several Noisy Intermediate-Scale Quantum (NISQ) hardware implementations were created and demonstrated in the past couple of years carrying advanced quantum technology. The term "NISQ" is often used interchangeably with "Near-Term" because the devices available in the next few years will be small and lack error correction. As one might expect, the fact that these near-term devices will be "small" and "noisy" limits their potential. "Small" does not refer to the physical size of the quantum computer but the amount of basic information. This variety of hardware adds another layer of complexity to the development of quantum computing algorithms and software. The developers have to stay updated with the recent trade-offs introduced by hardware.</p>
<p>Over the past few decades, scientists have come up with algorithms to make use of quantum computation. Shor's and Grover's algorithms are two of the most well-known examples of quantum algorithms with theoretically proven speedups over classical algorithms. However, there isn't a technology developed to counter NISQ's drawbacks. Some NISQ techniques have been proposed to handle this problem. The most popular one is Variational Quantum Eigensolver and Quantum Approximate Optimization Algorithm. The constraints of near-term hardware make the development of practical algorithms particularly challenging.</p>
<p><a target="_blank" href="https://aviyel.com/post/675/future-of-open-source-in-quantum-computing-a-brief-analysis">Click Here for full article</a></p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item><item><title><![CDATA[Mobile Security Tips and Best Practices 📱]]></title><description><![CDATA[It’s tough to stay secure nowadays, and that task is, even more intimidating now that we heavily rely on smartphones and mobile gadgets. A plethora of information such as personal social media accounts, emails, sensitive messages, and even bank detai...]]></description><link>https://pramitmarattha.com.np/mobile-security-tips-and-best-practices</link><guid isPermaLink="true">https://pramitmarattha.com.np/mobile-security-tips-and-best-practices</guid><category><![CDATA[mobile]]></category><category><![CDATA[Security]]></category><category><![CDATA[framework]]></category><dc:creator><![CDATA[Pramit Marattha]]></dc:creator><pubDate>Tue, 03 Aug 2021 17:13:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1628004997469/G0Y3ESXgB.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It’s tough to stay secure nowadays, and that task is, even more intimidating now that we heavily rely on smartphones and mobile gadgets. A plethora of information such as personal social media accounts, emails, sensitive messages, and even bank details are being stored on our smartphones. This data tends to be very sensitive and may contain valuable information, yet we store it despite its future consequences.</p>
<p>Mobile technology is evolving rapidly. In 2008, Mary Meeker, an analyst at Kleiner Perkins Caufield Byers, made a bold prediction, “Mobile to overtake fixed internet access by 2014”. Well, in 2021, we can undoubtedly say that she was absolutely right. Today, more than half of the population worldwide access the internet via mobile devices, while only 48 - 49% do so via laptops/desktops/tablets.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628005055918/-2JqbSO__.png" alt="unknown-resized.png" /></p>
<p>Most internet traffic comes from smartphone devices; most business-to-business deals are made through smartphones. Social media usage also tends to happen only on smartphones. Therefore, a business without a mobile or smartphone app is not an effective business at all. Literally, millions and billions of users are active on the internet, primarily through their smartphone devices.</p>
<p>So, it unlocks the gate of potential risk and security threats because of this massive user base. Hence, understanding the mobile security framework and protecting yourself plays a vital role in maximizing profits and minimizing potential risks or threats.</p>
<h1 id="understanding-security-frameworks">Understanding Security Frameworks.</h1>
<p>The information security framework is a dedicated security layer in conjunction with third-party software, which can be used to safeguard privacy.</p>
<p>There are five common security frameworks. They are as follows:</p>
<p> 1 . ISO 27001 and ISO 27002</p>
<p>It was created by the International Organization for Standardization (ISO), ISO 27001 and ISO 27002 certifications are considered the international standard for validating a cybersecurity program internally and across third parties applications.</p>
<p>2 . SOC2</p>
<p>Service Organization Control (SOC)  is a trust-based cybersecurity framework and auditing standard created by the American Institute of Certified Public Accountants (AICPA) to help verify that vendors and partners securely manage client data.</p>
<p>3 . NERC-CIP</p>
<p>North American Electric Reliability Corporation - Critical Infrastructure Protection (NERC-CIP) is a set of cybersecurity standards designed to help those in the utility and power sector reduce cyber risk and ensure the reliability of bulk electric systems.</p>
<p>4 . HIPAA</p>
<p>Health Insurance Portability and Accountability Act (HIPAA) is a cybersecurity framework that requires healthcare organizations to implement controls for securing and protecting the privacy of electronic health information.</p>
<p>5 . GDPR</p>
<p>General Data Protection Regulation (GDPR) is a security framework adopted in 2016 to strengthen data protection procedures for European Union citizens.</p>
<p>A security framework is a specific control and standard that helps to keep big business and government bodies safe from cyber-attacks.</p>
<h1 id="understanding-mobile-security-frameworks">Understanding Mobile Security Frameworks.</h1>
<p>The mobile security framework is also a dedicated security layer in conjunction with third-party software, which can be used to safeguard privacy. Except, it specializes only in the field to protect smartphone/mobile device users. Developing and maintaining a strong mobile security framework is a very crucial business because the use of mobile is continuing to skyrocket day by day.</p>
<p>According to the survey created by Statista, there were around 218 billion mobile application downloads alone in 2020, and this number is projected only to grow every year. This kind of skyrocketing growth creates massive opportunities to run businesses and for hackers and cybercriminals.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628005930356/Qo5R9jPnb.png" alt="unknown-1-resized.png" /></p>
<p>Cybercriminals and hackers are simply trailing the big numbers, taking significant advantage of the security loopholes and backdoors. Windows PCs are more likely to get hacked than Macs because there are a greater number of Windows PCs than Macs. Therefore, cybercriminals or hackers are more likely to spend more time perfecting and polishing their malware/virus and attacking Windows-based personal computers because there are more numbers out there to steal from. The same goes for Android vs. iOS. Android device users are more likely to suffer from security threats or attacks than iOS users because Android has a massive user base and is entirely open-source. Its entire source code is available for free/open to anyone accessing and developing apps using it.</p>
<p>In contrast, Apple iOS is a closed source. Even to publish a simple application, developers must verify themselves and go through the rigorous application process to publish their apps on the iOS platform. Therefore, iOS applications tend to suffer from fewer security threats. But iOS is also not entirely secure from security threats and loopholes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628006013124/dNV6-OxAr.png" alt="unknown-resized (1).png" /></p>
<h1 id="testing-mobile-security-frameworks">Testing Mobile Security Frameworks.</h1>
<p>The importance of mobile security is increasing day by day and becoming more crucial than ever. That is why developers have created mobile security frameworks and even open-sourced them. Whether you run Android/ iOS or any other kind of mobile OS, this pen-test software is destined and designed to mark and test the efficiency of the mobile app. MobSF is one of the very best, handy and easy-to-use tools. It is an entirely free and open-source tool that helps perform the security assessment of mobile/smartphone applications. MobSF provides excellent services like pen-testing, malware analysis, and security assessment.</p>
<p>Penetration testing using MobSF is straightforward. Simply drag &amp; drop the Android apk or iOS application in the analyzer panel.</p>
<p><a target="_blank" href="https://aviyel.com/post/583/mobile-security-tips-and-best-practices">Click Here for full article</a></p>
<p>Follow <a target="_blank" href="https://twitter.com/AviyelHq">@aviyelHQ</a> or <a target="_blank" href="https://aviyel.com/discussions">sign-up</a> on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.</p>
<p>Twitter =&gt;<a target="_blank" href="https://twitter.com/AviyelHq">https://twitter.com/AviyelHq</a></p>
<p>Official Site =&gt; <a target="_blank" href="https://aviyel.com/discussions">https://aviyel.com</a></p>
]]></content:encoded></item></channel></rss>