<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Femi-ige Muyiwa</title>
    <description>The latest articles on DEV Community by Femi-ige Muyiwa (@muyiwexy).</description>
    <link>https://dev.to/muyiwexy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F895352%2Fafe5d17c-0e5c-494f-b5aa-c0957e4b8f2b.jpg</url>
      <title>DEV Community: Femi-ige Muyiwa</title>
      <link>https://dev.to/muyiwexy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muyiwexy"/>
    <language>en</language>
    <item>
      <title>Run Postgres For Free: Top 3 Options</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Thu, 27 Mar 2025 12:29:29 +0000</pubDate>
      <link>https://dev.to/hackmamba/run-postgres-for-free-top-3-options-2pk6</link>
      <guid>https://dev.to/hackmamba/run-postgres-for-free-top-3-options-2pk6</guid>
      <description>&lt;p&gt;“When life gives you lemons, TAKE THEM; free stuff is cool.” ~ Teo Deleanu. &lt;/p&gt;

&lt;p&gt;And when life gives you &lt;strong&gt;PostgreSQL for free&lt;/strong&gt;, you take that too. Why? Because taking free stuff isn’t just cool; it’s the smartest thing to do. Whether you’re a developer building a side project or a startup testing the waters, running PostgreSQL without breaking the bank is a win-win.&lt;/p&gt;

&lt;p&gt;This article will show you the three top options for running &lt;a href="https://neon.tech/docs/get-started-with-neon/signing-up" rel="noopener noreferrer"&gt;PostgreSQL databases for free&lt;/a&gt;, from exploring some modern cloud hosting options to setting them up for development. &lt;/p&gt;

&lt;p&gt;By the end of this article, you’ll know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do these platforms compare?&lt;/li&gt;
&lt;li&gt;Which free-tier hosting platforms are the best (and what are their limitations)?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why PostgreSQL?
&lt;/h2&gt;

&lt;p&gt;PostgreSQL is a powerful open-source database that is constantly improved by a large community of developers. It supports familiar SQL queries, making it easy to use while offering the flexibility and reliability needed for modern full-stack apps. With over 35 years of open-source excellence, it is one of the greatest relational databases of all time, trusted by developers worldwide. It is a truly open-source project with no hidden licensing fees, making it a cost-effective choice for any project.&lt;/p&gt;

&lt;p&gt;Also, PostgreSQL is known for its rock-solid data integrity as it follows the Atomicity, Consistency, Isolation, and Durability principles (ACID). In doing so, PostgreSQL &lt;strong&gt;never loses, corrupts, or allows inconsistent data&lt;/strong&gt;, which is critical for applications like banking and healthcare.&lt;/p&gt;

&lt;p&gt;One of PostgreSQL’s standout features is its concurrency handling through its Multi-Version Concurrency Control (MVCC). This feature allows multiple transactions to read the same data without blocking writes. Here is an SQL query that represents two database transactions running in separate sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nx"&gt;Transaction&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;FROM&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="nx"&gt;WHERE&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nx"&gt;Reads&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;
&lt;span class="nx"&gt;UPDATE&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shipped&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;WHERE&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nx"&gt;Transaction&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;FROM&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="nx"&gt;WHERE&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nx"&gt;Reads&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;old&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="nx"&gt;before&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;committed&lt;/span&gt;
&lt;span class="nx"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this technique, Session B sees a consistent snapshot of the data without being blocked by Session A’s update, making PostgreSQL a reliable choice for highly concurrent apps such as e-commerce, finance, and collaborative platforms.&lt;/p&gt;

&lt;p&gt;Now, the moment you’ve been waiting for: here are the top three free-tier hosting solutions for the Postgres database. You’ll get to see why developers love them, as well as a quick start guide and some of their limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Managed Postgres Comparison Table&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here is a like-for-like comparison table summarizing the features of some of the best free-tier Postgres hosting platforms. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Neon&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Aiven&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Render&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Easiest for beginners&lt;/strong&gt; – Instant provisioning, database branching, and serverless architecture.&lt;/td&gt;
&lt;td&gt;Moderate – Supports multiple open-source technologies but limited to one service on the free plan.&lt;/td&gt;
&lt;td&gt;Moderate – Unified platform but limited to one free database instance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free Tier Storage Disk Space&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.5 GB&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute Hours&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;191.9h/month&lt;/td&gt;
&lt;td&gt;Not specified&lt;/td&gt;
&lt;td&gt;Not specified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Postgres Versions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17, 16, 15, 14&lt;/td&gt;
&lt;td&gt;17, 16, 15, 14, 13&lt;/td&gt;
&lt;td&gt;16, 15, 14, 13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Branching&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (Full data branching and Schema-only branching &lt;em&gt;BETA&lt;/em&gt;)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud Providers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multiple (AWS and Azure)&lt;/td&gt;
&lt;td&gt;Single (DigitalOcean)&lt;/td&gt;
&lt;td&gt;Single (AWS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Autoscaling can burn through compute hours.&lt;/td&gt;
&lt;td&gt;Max 20 connections, no connection pooling.&lt;/td&gt;
&lt;td&gt;30-day limit, no backups, single instance only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;large enterprise workloads as well as small projects, MVPs, and scalable applications.&lt;/td&gt;
&lt;td&gt;Testing and small projects.&lt;/td&gt;
&lt;td&gt;Small development and testing.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Neon
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; provides a cloud-based, scalable implementation of PostgreSQL that can run on your physical hardware or through their managed services. Its architecture is separated into “&lt;strong&gt;compute&lt;/strong&gt;” (for Postgres) and “&lt;strong&gt;storage&lt;/strong&gt;” (a multi-tenant key-value store for Postgres pages), allowing Neon to gain true serverless capabilities.&lt;/p&gt;

&lt;p&gt;Separating these architectures allows Neon to autoscale its compute resources depending on the activity period while maintaining data separately in a multi-tenant storage system. This architecture allows users to set up resources as soon as requested (instant provisioning), making it effective for managing costs since you only pay for the compute resources you use. This approach makes Neon reliable and cost-efficient compared to traditional database architectures, where storage and computing are tightly coupled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Developers Love Neon&lt;/strong&gt;&lt;br&gt;
Neon offers a generous free tier option, enabling developers to build small projects and MVPs for a good period of time. Here are some of the benefits of the Neon PostgreSQL free tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can have up to 10 projects, with each project able to own 10 branches.&lt;/li&gt;
&lt;li&gt;Supports connection pooling through PgBouncer, enabling up to 10,000 concurrent connections.&lt;/li&gt;
&lt;li&gt;Provides automatic backups through its "Point-in-Time Restore" (PITR) feature.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hackernoon.com/building-a-web-app-this-method-makes-it-faster-safer-and-smarter" rel="noopener noreferrer"&gt;&lt;strong&gt;Database branching&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; This option allows you to create different environments (Dev, Staging, and Production) for your Postgres. You can also create some backup, as a new branch always contains data from the main branch.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The free tier offers a 0.5 GB storage limit, 191.9 compute hours/month, and 5GB of data transfer.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ydw2c3f02ua6nxu2zzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ydw2c3f02ua6nxu2zzm.png" alt="project summary" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It supports Postgres versions 17, 16, 15, and 14.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63obty8vptvrnecajtbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63obty8vptvrnecajtbd.png" alt="postgres version" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supports multiple cloud service providers and has access to all regions available to these providers.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvoqdgq45efj406xjyic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvoqdgq45efj406xjyic.png" alt="aws service provider" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2yx3w9intyby0u7aoxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2yx3w9intyby0u7aoxl.png" alt="Azure service provider" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Start Guide&lt;/strong&gt;&lt;br&gt;
You can &lt;a href="https://console.neon.tech/realms/prod-realm/login-actions/registration?client_id=neon-console&amp;amp;tab_id=QsRc-NDpu5c&amp;amp;client_data=eyJydSI6Imh0dHBzOi8vY29uc29sZS5uZW9uLnRlY2gvYXV0aC9rZXljbG9hay9jYWxsYmFjayIsInJ0IjoiY29kZSIsInN0IjoiMXFZbDRFWGdmcUx6cVZFclQ4bmZNQT09LCwsIn0&amp;amp;" rel="noopener noreferrer"&gt;sign up to Neon&lt;/a&gt; using an email and password or with other third-party providers like Google, GitHub, or Microsoft. Then, create a new project using any configuration you prefer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4u3w6bmxxlqivpb5ejcu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4u3w6bmxxlqivpb5ejcu.png" alt="get started with neon project" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation&lt;/strong&gt;&lt;br&gt;
Though autoscaling can improve performance during high-activity periods, it can easily burn through the compute hours during the free trial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aiven
&lt;/h2&gt;

&lt;p&gt;Unlike Neon, &lt;a href="https://aiven.io/" rel="noopener noreferrer"&gt;Aiven&lt;/a&gt; provides many open-source managed data infrastructures, such as PostgreSQL Apache Cassandra, Apache Kafka, Apache Kafka Connect, Apache Kafka MirrorMaker 2, Elasticsearch, Grafana, InfluxDB, M3, M3 Aggregator, MySQL, and Redis. It’s a jack of all trades regarding its support for open-source technology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Developers Love Aiven&lt;/strong&gt;&lt;br&gt;
Aiven supports deployment across various cloud providers, allowing users to choose the best infrastructure for their needs. Aiven offers access to its service using the free plan (PostgreSQL, MySQL, ValKey) or a 30-day free trial. When using the free plan, you can only access one service, but Aiven offers a 30-day free trial that can allow you to access all the services. &lt;/p&gt;

&lt;p&gt;Aiven for PostgreSQL is a fully managed and hosted relational database service, and it offers features that developers can use indefinitely, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It supports Postgres versions 17, 16, 15, 14, and 13.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8puybat5f5jsewseq1i5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8puybat5f5jsewseq1i5.png" alt="postgres version" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The free tier consists of a single node, 1 CPU per virtual machine, 1 GB of RAM, and 5 GB of disk storage.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu33817ca2r21nmlgdih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnu33817ca2r21nmlgdih.png" alt="free plan" width="622" height="908"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Management through the Aiven Console, CLI, API, Terraform Provider, or Kubernetes Operator.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monitoring for metrics and logs.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj588eji4imtafe4393n6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj588eji4imtafe4393n6.png" alt="metrics" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supports backups for disaster recovery.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Start Guide&lt;/strong&gt;&lt;br&gt;
You can &lt;a href="https://console.aiven.io/signup" rel="noopener noreferrer"&gt;sign up to Aiven&lt;/a&gt; using an email or with any of its third-party authentication provider options. Afterward, you must log in to the console and follow the onboarding process to complete your registration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b65g8ptyye4z2lrb1qo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b65g8ptyye4z2lrb1qo.png" alt="login" width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwikenizn9otboa63fk9h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwikenizn9otboa63fk9h.png" alt="onboarding" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you finish that, you are greeted with a page listing services you can create. Select the PostgreSQL service and set up your service using your desired configuration, then click ‘&lt;strong&gt;Create free service&lt;/strong&gt;’ to deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb0wfbqniaejy0m6zxvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb0wfbqniaejy0m6zxvx.png" alt="postgres service" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;br&gt;
Here are some of the limits to consider when using Aiven Postgres free tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It only supports a maximum of 20 connections, and connection pooling is not available to help manage multiple client connections.&lt;/li&gt;
&lt;li&gt;Limited support: Aiven doesn’t provide access to dedicated support teams and, instead, relies solely on the &lt;a href="https://aiven.io/community/forum/" rel="noopener noreferrer"&gt;Aiven Community Forum&lt;/a&gt; for user assistance.&lt;/li&gt;
&lt;li&gt;The free plan is not covered by the &lt;a href="https://aiven.io/sla" rel="noopener noreferrer"&gt;Aiven Service Level Agreement&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A single cloud provider (DigitalOcean), limited service region, and service plan for the free plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Render
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://render.com/" rel="noopener noreferrer"&gt;Render&lt;/a&gt; is a more traditional hosting platform that can build and deploy your applications, websites, and databases. As a unified platform, Render is an awesome choice for both seasoned developers and beginners, as you do not have to worry about using multiple platforms to host your application and your database(s). It can run various projects, from static sites and web applications to background workers, APIs, cron jobs, and managed databases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Developers Love Render&lt;/strong&gt;&lt;br&gt;
Apart from Render’s user-friendly interface, it offers a free PostgreSQL hosting plan for development and testing, hobby projects, and MVPs. Here is an overview of some of its features and benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fixed Resource Allocation:&lt;/strong&gt; The free PostgreSQL plan provides 256 MB RAM, 1 GB storage capacity, and 0.1 CPU, which can be enough for small-scale development.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sa2zk408xiu29svrxvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8sa2zk408xiu29svrxvw.png" alt="pricing options" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It supports Postgres versions 16, 15, 14, and 13.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The free PostgreSQL plan has all regions available to other paid plans.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3dl2pg17vk58j7c9bok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3dl2pg17vk58j7c9bok.png" alt="regions" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It allows you to integrate your PostgreSQL database with the other services available to Render. So, if you have an existing project hosted on Render and want to host a database for that project, Render gives you the option to do that during the database setup.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2g5sa9a5z779t25l6eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2g5sa9a5z779t25l6eo.png" alt="add  project" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick Start Guide&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://dashboard.render.com/register" rel="noopener noreferrer"&gt;Sign up to Render&lt;/a&gt; using an email or any third-party authentication provider option. Afterward, you will be greeted with various service types that Render offers. Select &lt;strong&gt;New PostgreSQL&lt;/strong&gt; and set up the service with your desired configurations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F007v1ullooo127y9b995.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F007v1ullooo127y9b995.png" alt="new postgres" width="800" height="358"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pibm6fxlw3beac8brep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pibm6fxlw3beac8brep.png" alt="new database" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;br&gt;
Here are some of the limitations to consider when choosing the free tier option for Render:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Free PostgreSQL database has a 30-day limit and will expire after that deadline. It has a 14-day grace period after the deadline, which will cause Render to delete the database if you do not update the plan.&lt;/li&gt;
&lt;li&gt;It has a single instance limit for the PostgreSQL database. You can have only &lt;em&gt;one&lt;/em&gt; &lt;strong&gt;&lt;em&gt;active&lt;/em&gt;&lt;/strong&gt; Free PostgreSQL database for any given workspace.&lt;/li&gt;
&lt;li&gt;It doesn't support database backups.&lt;/li&gt;
&lt;li&gt;Downtime or maintenance would cause the database to be temporarily unavailable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Neon, Aiven, and Render are outstanding, cost-effective database options with great value. Each has standout features that, depending on your needs, can give you a great developer experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Neon&lt;/strong&gt; stands out with its serverless architecture and developer-friendly features, such as database branching and generous compute hours. Its instant provisioning and transparent resource allocation make it perfect for large enterprises, rapid prototyping, and early-stage startups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aiven&lt;/strong&gt; delivers reliability with its fixed 5GB storage and support for multiple Postgres versions. While the free tier is limited to one service, its monitoring tools and backup support make it ideal for learning and small production workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render&lt;/strong&gt; shines with its unified platform approach, letting you host your applications and databases in one place. Though time-limited, its straightforward setup and integration capabilities make it an excellent choice for full-stack applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;So, what are you waiting for?&lt;/strong&gt; Pick the best platform for your project and start building today without spending a dime!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;If you're considering using PostgreSQL the traditional way, here are guides to install it on macOS, Linux, or Windows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neon.tech/postgresql/postgresql-getting-started/install-postgresql-macos" rel="noopener noreferrer"&gt;Install PostgreSQL on macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neon.tech/postgresql/postgresql-getting-started/install-postgresql" rel="noopener noreferrer"&gt;Install PostgreSQL on Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neon.tech/postgresql/postgresql-getting-started/install-postgresql-linux" rel="noopener noreferrer"&gt;Install PostgreSQL on Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>postgres</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>5 Must-Watch Tutorials to Build Your SaaS App in 2025</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Thu, 27 Feb 2025 13:29:17 +0000</pubDate>
      <link>https://dev.to/hackmamba/5-must-watch-tutorials-to-build-your-saas-app-in-2025-b89</link>
      <guid>https://dev.to/hackmamba/5-must-watch-tutorials-to-build-your-saas-app-in-2025-b89</guid>
      <description>&lt;p&gt;Today, building a Software as a Service (SaaS) application is easier than ever, at least on paper. With no-code tools like Webflow and serverless platforms handling the heavy lifting, you can spin up a functional product in record time. But getting from an idea to a successful launch? That’s where things get tricky.  &lt;/p&gt;

&lt;p&gt;It’s more than writing code. You need the right tools, a solid market approach, and a willingness to keep learning. The good news? If you know where to look, there’s a wealth of knowledge out there.  &lt;/p&gt;

&lt;p&gt;To simplify things, I’ve rounded up five must-watch video tutorials to guide you through the process. Whether you’re a seasoned developer or just testing the waters, these videos will help you build, launch, and grow a SaaS app that makes an impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Building a Finance Manager SaaS Platform
&lt;/h2&gt;

&lt;p&gt;The finance industry is a large sector with many market opportunities. Whether you are an entrepreneur launching a fintech startup or an individual hoping to solve a market problem, building a finance app can provide people with better tools to track expenses, budget effectively, and make informed financial decisions. By creating a finance app, you empower users to take control of their money through features like automation and statistics, giving them a better idea of how their money comes in and goes out.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll learn how to build a finance manager app that tracks daily transactions, income, and expenses while visualizing them with clear graphs. You’ll also see how to add a point-in-time feature so users can analyze their data for specific date ranges. There’s a subscription-based element that unlocks premium features like connecting bank accounts and importing transactions, giving users more flexibility with their finances.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/N_uNKAus0II"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You’ll start by setting up &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; for the project and then integrating route and API management using &lt;a href="https://hono.dev/docs/" rel="noopener noreferrer"&gt;Hono&lt;/a&gt;. &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Shadcn UI&lt;/a&gt; makes UI prototyping faster, so you won’t have to build every component from scratch. The video also covers &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; authentication for protected routes and demonstrates how &lt;a href="http://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; &lt;a href="http://neon.tech/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; fits in as a serverless solution for SQL databases.&lt;/p&gt;

&lt;p&gt;You’ll use &lt;a href="https://orm.drizzle.team/" rel="noopener noreferrer"&gt;Drizzle ORM&lt;/a&gt; to manage TypeScript-to-Postgres mapping, so you will never have to juggle low-level SQL queries. Drizzle ORM helps maintain a safer interaction between your database and the Typescript project while enabling efficient schema management.&lt;/p&gt;

&lt;p&gt;You won’t see how to connect bank accounts in this video, but you do get a neat way to import transactions. You can customize your table headers with predefined names, letting you decide which columns to keep or skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Build a SaaS App With Django, Stripe, Neon PostgreSQL, TailwindCSS, GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Knowing what tools, when, and how to use them remains invaluable in your programming journey. It is a huge part of being an innovator or pioneer and the foundation of being a great programmer. &lt;/p&gt;

&lt;p&gt;This excellent tutorial will teach you how to build a foundational SaaS application using Django, covering authentication, data modeling, and payment integrations. You’ll understand why Python is a go-to language with its rich library ecosystem that streamlines common functionalities. There’s also a focus on setting up a scheduled production worker to sync user subscriptions at intervals.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WbNNESIxJnY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You’ll start by configuring a Python project with Django to manage views, routes, and static files. The video also shows how to style the front end using &lt;a href="https://flowbite.com/" rel="noopener noreferrer"&gt;Flowbite&lt;/a&gt; and &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;. The tutorial then walks you through preparing Django for a production environment and deploying it to &lt;a href="https://railway.com/" rel="noopener noreferrer"&gt;Railway’s cloud platform&lt;/a&gt; via Docker containers.&lt;/p&gt;

&lt;p&gt;The video explores subscription and payment integration in Stripe, showing how to handle recurring payments and manage user access based on their subscription status. Next, you’ll handle user authentication with &lt;a href="https://docs.allauth.org/en/latest/" rel="noopener noreferrer"&gt;Django Allauth&lt;/a&gt; by creating social authentication using GitHub authentication and linking user data with Stripe on registration.&lt;/p&gt;

&lt;p&gt;This tutorial also highlights using PostgreSQL as the database option in the Django project, specifically focusing on &lt;a href="http://neon.tech/" rel="noopener noreferrer"&gt;Neon PostgreSQL&lt;/a&gt;. Neon is a managed form of PostgreSQL that eases development processes through its serverless architecture, allowing developers to focus on building rather than infrastructure management. The video tutorial emphasizes Neon's quick database setup and serverless approach, which means it can respond to the growing demand for your SaaS product, and the server only runs when you need it to run.&lt;/p&gt;

&lt;p&gt;This is a beginner-friendly guide that helps you anticipate common pitfalls. You’ll learn to implement Stripe with Django in a way that gracefully handles subscription logic, user accounts, and data syncing, giving you a solid foundation to build and scale your SaaS product.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. How To Build A $1,000,000 SaaS In 7 Hours
&lt;/h2&gt;

&lt;p&gt;The saying “There is nothing new under the sun” might be true in some cases, but in others, innovation comes not from creating something entirely new but from improving existing ideas by addressing their weaknesses. Building a SaaS product doesn’t mean you must be original or a pioneer in the field of interest. In a competitive market, one or two key differences in its abilities could differentiate a good product from a great product. If you want to explore that, then this video is for you.&lt;/p&gt;

&lt;p&gt;This video provides more insights into building SaaS solutions on already existing ones while improving on their weaknesses. It shows how to use the latest Next.js features to build a clone of &lt;strong&gt;ParityDeals&lt;/strong&gt;, an application that offers discounts based on the user's country. The finished clone improves upon &lt;strong&gt;ParityDeals&lt;/strong&gt; banner customization by introducing custom font sizes and manual &lt;strong&gt;CSS prefix&lt;/strong&gt; configurations. There’s a permission-based system that differentiates users' access based on their subscriptions. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pWV-8PW1l2A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You’ll set up &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; with &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Shadcn UI&lt;/a&gt; and &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; for styling and then configure &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; for authentication. The video covers &lt;a href="http://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; &lt;a href="http://neon.tech/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; database branching for development and uses Neon to store product data, customizations, and subscriptions. &lt;a href="http://Drizzle%20ORM" rel="noopener noreferrer"&gt;Drizzle ORM&lt;/a&gt; handles database setup, including schema, migrations, and credentials.&lt;/p&gt;

&lt;p&gt;One of the best parts of this tutorial is its use of caching. It implements three levels, global, user-specific, and ID-specific, to optimize data storage and retrieval based on relevance.&lt;/p&gt;

&lt;p&gt;Additionally, it revalidates cached data and updates it correctly when changes occur, such as product edits or deletions. This keeps information up to date without delays, making the tutorial a great resource for enhancing existing product features.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. SaaS Automation Builder
&lt;/h2&gt;

&lt;p&gt;Automation eliminates many cognitive or physical limitations humans face, making it useful for time-sensitive or repetitive tasks. This makes it crucial in production as it improves productivity while potentially saving on labor. This tutorial demonstrates how to build an automation platform called &lt;strong&gt;Fuzzie.&lt;/strong&gt; The finished SaaS app allows users to create and edit workflows by setting a trigger (Google Drive) with different actions. Each workflow has a draggable canvas with a minimap and controls for centering and zooming in or out of the canvas page. Users can save their workflow to a database or publish it.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XkOXNlHJP6M"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The tutorial starts by creating a &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; project and setting up &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Shadcn UI&lt;/a&gt; and &lt;a href="https://ui.aceternity.com/" rel="noopener noreferrer"&gt;Aceternity UI&lt;/a&gt; for premade front-end components, with &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; for styling. Next, you will use &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma ORM&lt;/a&gt; to create data models and generate schemas for Neon's Postgres database. The tutorial also covers file uploads using &lt;a href="https://uploadcare.com/" rel="noopener noreferrer"&gt;Uploadcare&lt;/a&gt;, &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; to handle authentication, and creating a billing system with Stripe that allows users to purchase different plans.&lt;/p&gt;

&lt;p&gt;You can never overstate the importance of automation in small-scale to large-scale processes. This video buttresses it through its implementation and emphasizes the usability of features like the draggable canvas with a minimap, which allows users to navigate their workflows easily, adapting to the complexity and size of their projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. SaaS AI Chatbot - Email Marketing, Next.js, Clerk, Neon, Uploadcare, Cloudways, Bun, Stripe, Pusher
&lt;/h2&gt;

&lt;p&gt;At this time, it feels more like a disadvantage not to leverage some AI features within your SaaS product. Many software services use AI to improve product features, either as an agent or as a RAG (Retrieval Augmented Generation) embedded feature. This addition provides a great user experience, thus facilitating the better adoption of said product.&lt;/p&gt;

&lt;p&gt;Here is a great tutorial on creating an artificially intelligent chatbot that acts as a sales representative. The chatbot is effective in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starting a conversation with a website visitor and requesting their email address.&lt;/li&gt;
&lt;li&gt;Providing answers based on user responses.&lt;/li&gt;
&lt;li&gt;Sending a link to the user, which can take them to a portal page or a payment form, depending on the conversation flow.&lt;/li&gt;
&lt;li&gt;Managing conversation flow by sending an email notification to the business owner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, you’ll add AI into custom domains and embed chatbots into websites. Authenticated users can track domain income, monitor data metrics, and customize chatbot appearance and greetings based on their subscription. The app enables chatbot training by letting business owners set bot training and help desk questions. Additionally, it supports product sales through Stripe integration, allows users to manage billing and subscriptions, schedule appointments manually or via the chatbot, and conduct email marketing based on captured leads.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9pCsyBlpmrc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll create a &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; project with &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; and build custom authentication pages &lt;a href="http://Clerk" rel="noopener noreferrer"&gt;for Clerk&lt;/a&gt; without the watermark. This means you’ll create a custom Clerk authentication component, allowing you to have a UI without the Clerk branding in the authentication component. You’ll then set up file uploads using &lt;a href="https://uploadcare.com/" rel="noopener noreferrer"&gt;Uploadcare&lt;/a&gt; and create custom theming with &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Shadcn UI&lt;/a&gt; for light and dark modes. A real-time chat feature will be built using &lt;a href="https://pusher.com/" rel="noopener noreferrer"&gt;Pusher&lt;/a&gt; as a secure layer between the server and the client.&lt;/p&gt;

&lt;p&gt;Toward the end, you’ll integrate OpenAI and use prompt engineering to customize chatbot responses. &lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; will serve as the database, with &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma ORM&lt;/a&gt; managing users, domains, chatbots, billing, help desks, and customer interactions.&lt;/p&gt;

&lt;p&gt;This tutorial offers a hands-on guide to integrating AI for client interactions. While not entirely beginner-friendly, it demonstrates AI’s ability to manage early conversations and ensure prompt responses. The standout feature is its adaptive AI, which makes clients feel heard and enhances customer relations without the immediate interference of the business owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;From finance management and subscription-based platforms to AI chatbots and automation tools, these five tutorials highlight the variety of directions your SaaS project can take. One feature that stands out across all these tutorials is using &lt;a href="https://neon.tech" rel="noopener noreferrer"&gt;Neon PostgreSQL&lt;/a&gt; as the database of choice. No matter which technologies or frameworks you adopt, Neon can help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scale on demand without manual intervention&lt;/li&gt;
&lt;li&gt;Save time setting up and managing databases&lt;/li&gt;
&lt;li&gt;Integrate with TypeScript, Python, Next.js, and other common SaaS stacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building a SaaS product doesn’t have to be a giant leap of faith. With guides like these, modern platforms like Next.js and Django, and serverless databases like &lt;a href="https://neon.tech/" rel="noopener noreferrer"&gt;Neon&lt;/a&gt;, you can experiment, iterate, and ship faster. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to start building your own SaaS app?&lt;/strong&gt; Pick a tutorial, dive in, and take the first step toward launching your product. Whether building from scratch or improving an existing idea, the right tools and guidance can help you turn your vision into reality.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building AI-powered mobile app with RAG, pgvector &amp; OpenAI</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Wed, 21 Feb 2024 10:34:42 +0000</pubDate>
      <link>https://dev.to/hackmamba/building-ai-powered-mobile-app-with-rag-pgvector-openai-31ma</link>
      <guid>https://dev.to/hackmamba/building-ai-powered-mobile-app-with-rag-pgvector-openai-31ma</guid>
      <description>&lt;p&gt;Retrieval augmented generation (RAG) is an AI technique for enhancing the response capabilities of large language models (LLMs) by providing them with an external source of knowledge. This framework ensures that the model can access current and reliable facts because the users can access the model sources.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll learn how to implement the RAG technique by building a mobile application that gives a detailed response with respect to an external data source (CSV file) when queried. We’ll also cover how to implement this functionality with &lt;a href="https://neon.tech/?ref=hm" rel="noopener noreferrer"&gt;Neon Postgres&lt;/a&gt;, &lt;a href="https://flutter.dev/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;Flutter framework&lt;/a&gt;, and &lt;a href="https://auth0.openai.com/u/login/identifier?state=hKFo2SBKdWQzNEJ4MnlFRm9NZlM5ZmFKblRSdUpoOUxENzdRZqFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIFcyZTRoOUxvQ3RNUXJ2Sm8xWU91UXhFUnhNM2oxd01So2NpZNkgRFJpdnNubTJNdTQyVDNLT3BxZHR3QjNOWXZpSFl6d0Q" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out the link to the &lt;a href="https://github.com/muyiwexy/neon_rag_with_openai/tree/full-code?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; containing all the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you begin, this tutorial will explore the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a Neon Postgres project, database, and table.&lt;/li&gt;
&lt;li&gt;Component of RAG&lt;/li&gt;
&lt;li&gt;Building a Flutter application&lt;/li&gt;
&lt;li&gt;Connecting Neon to the Flutter application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;We’ll need a few things before getting started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A good understanding of the &lt;a href="https://flutter.dev/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; framework and &lt;a href="https://dart.dev/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;dart programming&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://console.neon.tech/sign_in" rel="noopener noreferrer"&gt;Neon account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An OpenAI API key; thus, you need an &lt;a href="https://auth0.openai.com/" rel="noopener noreferrer"&gt;OpenAI account&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Breaking down the technologies
&lt;/h2&gt;

&lt;p&gt;Let’s talk a bit about the tools we’ll be using. &lt;a href="https://neon.tech/?ref=hm" rel="noopener noreferrer"&gt;Neon&lt;/a&gt; is a fully managed serverless Postgres with a generous free tier that provides separate storage and computing to offer autoscaling, branching, and bottomless storage. Neon is fully open source under the Apache 2.0 licenses, and you can find the &lt;a href="https://github.com/neondatabase/neon?ref=hm" rel="noopener noreferrer"&gt;neondatabase&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;We’ll also be using the pgvector Postgres extension on Neon. &lt;a href="https://neon.tech/docs/extensions/pgvector?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;pgVector&lt;/a&gt; is a Postgres extension that works with vector embeddings for storage, similarity search, and more. &lt;/p&gt;

&lt;p&gt;Enabling the pgvector extension in your database simplifies storing vector embeddings as well as easy querying using the inner product (&lt;code&gt;&amp;lt;#&amp;gt;&lt;/code&gt;) or cosine distance (&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: vector embeddings are numerical representations of data that capture semantic relationships and similarities&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project further explores the use case of the RAG technique by employing the Flutter framework. Flutter is a UI development toolkit developed by Google that supports cross-platform app-building using the same codebase. The use of the Flutter application for this project is to give a programmatic and visual understanding of how the RAG technique works. Thus, we will build a simple chatbot that offers a response based on the external data source provided at a time.&lt;/p&gt;

&lt;p&gt;Finally, the project comes to life using both technologies by pairing with a Large Language Model (LLM) via &lt;a href="https://auth0.openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; to process the external data source and deliver a response in natural language. &lt;/p&gt;

&lt;p&gt;Some paragraphs above mentioned a mystery phrase called &lt;strong&gt;vector embeddings&lt;/strong&gt;, leading to more questions. The coming sections will demystify this concept by giving a better understanding of the things needed to implement the RAG technique in your application.&lt;/p&gt;

&lt;p&gt;Let's begin without further ado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Neon Postgres project
&lt;/h2&gt;

&lt;p&gt;Neon offers a simple method of setting up a project — streamlined to three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project name&lt;/li&gt;
&lt;li&gt;Postgres version&lt;/li&gt;
&lt;li&gt;Database name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This option is made available after signing into your Neon account. On the project setup page, there are more options to explore; for example, you can change the branch name to any other name, but advisably, leave it as &lt;code&gt;main&lt;/code&gt; for now and click &lt;code&gt;Create project&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" alt="Neon sign-in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" alt="Create project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" alt="More options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, on the homepage, you’ll find a popup containing all the connection details required to connect your application(s) to a Neon database. Copy these details to a safe file, such as a JSON file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" alt="Connection details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: For security reasons, you should use a &lt;code&gt;.env&lt;/code&gt; file to secure your connection details. Check out this &lt;a href="https://developer.school/tutorials/how-to-use-environment-variables-with-flutter-dotenv" rel="noopener noreferrer"&gt;article&lt;/a&gt; to learn more about how to use &lt;code&gt;flutter_dotenv&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With Neon, you can manage your database using a few options, such as a &lt;a href="https://neon.tech/docs/reference/cli-databases?ref=hm" rel="noopener noreferrer"&gt;Command Line Interface (CLI)&lt;/a&gt;, the &lt;a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api?ref=hm" rel="noopener noreferrer"&gt;Neon API&lt;/a&gt;, or a &lt;a href="https://neon.tech/docs/get-started-with-neon/query-with-neon-sql-editor?ref=hm" rel="noopener noreferrer"&gt;Structured Query Language&lt;/a&gt; (SQL) tool. Neon also provided an SQL Editor to write SQL commands directly on the console. You are in luck with SQL commands, as Flutter supports a Dart package &lt;code&gt;Postgres&lt;/code&gt; that makes this possible.&lt;/p&gt;

&lt;p&gt;The coming sections will shed more light on using Flutter and Neon Postgres pgvector extension and OpenAI to implement RAG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Flutter application
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Cloning the UI template
&lt;/h2&gt;

&lt;p&gt;The project implements a Flutter template for faster development by making the UI code available using GitHub. To begin, clone the template from the &lt;a href="https://github.com/muyiwexy/neon_rag_with_openai?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;repository&lt;/a&gt; using the command below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/muyiwexy/neon_rag_with_openai.git&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: The template contains the Flutter UI code and some defragmented codes, which will cause some debug errors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After cloning the project, run the command below to obtain all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies.:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We employed the &lt;strong&gt;Model View Controller&lt;/strong&gt; (MVC) architecture to handle specific development aspects of the application and give it a clear separation of concern. The architecture helps maintain readability by separating the business (core) logic from the UI or view (presentation layer). The cloned template won't compile at the moment as some things must be implemented as you progress.&lt;/p&gt;

&lt;p&gt;Here’s a helpful ASCII representation of the main Flutter development folder (lib) using the MVC design pattern:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home_page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;service_config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;dependency_injection&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;provider_locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Notes: The intended data source is a comma-separated values (CSV) file called &lt;code&gt;mydata.csv&lt;/code&gt; in the assets folder. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The external dart plugins used during the project (they are in the template &lt;code&gt;pubspec.yaml&lt;/code&gt; file) :&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;csv&lt;/span&gt;
  &lt;span class="nx"&gt;flutter_dotenv&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;
  &lt;span class="nx"&gt;postgres&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Implementing the RAG technique
&lt;/h2&gt;

&lt;p&gt;Implementing a Flutter project as a RAG application involves the functionalities being classed into two components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indexing&lt;/li&gt;
&lt;li&gt;Retrieval&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Indexing
&lt;/h2&gt;

&lt;p&gt;Indexing allows the system to receive information from an extensive data set by creating means of data collection, encoding, and storage. To successfully index the intended data &lt;strong&gt;(mydata.csv),&lt;/strong&gt; you will need to approach the indexing component in three processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load&lt;/li&gt;
&lt;li&gt;Split&lt;/li&gt;
&lt;li&gt;Store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Load&lt;/strong&gt;&lt;br&gt;
The load process is usually offline; thus, with the CSV package, you can convert a CSV file to a list of &lt;code&gt;Strings&lt;/code&gt; with the &lt;code&gt;convert&lt;/code&gt; method of the &lt;code&gt;CsvToListConverter()&lt;/code&gt; class. &lt;/p&gt;

&lt;p&gt;To load a CSV file, head to the &lt;code&gt;lib/home&lt;/code&gt; directory and create a new controller directory. Within this newly created directory, create a file called &lt;code&gt;openai_indexing_services.dart&lt;/code&gt; to handle the abstraction of the business logic from the UI. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;openai_indexing_services.dart&lt;/code&gt; will handle all the abstractions for the methods in this project, leading to some back and forth in the coming sections. For the first method, create a function &lt;code&gt;loadCSV()&lt;/code&gt; to handle loading the CSV file in this project.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadCSV&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Still, within the &lt;code&gt;lib/home/controller&lt;/code&gt; directory, create another file called &lt;code&gt;openai_indexing_services_impl.dart&lt;/code&gt; to handle the implementation of the abstraction &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; above. It does this using inheritance — one of the fundamentals of &lt;strong&gt;object-oriented programming&lt;/strong&gt; (OOP). &lt;/p&gt;

&lt;p&gt;The implementation of the &lt;code&gt;loadCSV()&lt;/code&gt; function uses the &lt;code&gt;loadString&lt;/code&gt; method in the &lt;code&gt;rootbundle&lt;/code&gt; property to get the CSV file from its root directory. Then, the &lt;code&gt;convert&lt;/code&gt; method in the &lt;code&gt;CsvToListConverter()&lt;/code&gt; class (called from the &lt;code&gt;CSV&lt;/code&gt; package) converts the CSV document to a list of lists (with each inner list representing a row of the CSV documents) and then returns the value.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadCSV&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading File... &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;rawcsvFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;rootBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assets/mydata.csv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;csvData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;CsvToListConverter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawcsvFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitMapJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;csvData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Split&lt;/strong&gt;&lt;br&gt;
Next, you’ll need to split this data into smaller chunks and embed them as vectors to aid the indexing and passing of large data into models, as large data takes too long to search over.&lt;/p&gt;

&lt;p&gt;To split and embed the loaded data into chunks, update the abstraction in the &lt;code&gt;lib/home/controller/openai_indexing_services.dart&lt;/code&gt; with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadCSV&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitToChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;splitToChunks&lt;/code&gt; method takes in the value returned from the &lt;code&gt;loadCSV&lt;/code&gt; (csvDoc) as an argument and returns a list of lists of &lt;code&gt;Strings&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The implementation of the &lt;code&gt;splitToChunks&lt;/code&gt; method in the &lt;code&gt;lib/home/controller/openai_indexing_services_impl.dart&lt;/code&gt; takes a list of lists (&lt;code&gt;csvDoc&lt;/code&gt;) as a parameter, where each inner list in the &lt;code&gt;csvDoc&lt;/code&gt; represents a row in a CSV document. &lt;/p&gt;

&lt;p&gt;Then, it initializes an empty list &lt;code&gt;chunkList&lt;/code&gt; to store chunks of split data ( for later)  and iterates over each row in &lt;code&gt;csvDoc&lt;/code&gt; using a &lt;strong&gt;for loop&lt;/strong&gt;, starting from the second row (&lt;code&gt;var i = 1&lt;/code&gt;), treating each row as a document.&lt;/p&gt;

&lt;p&gt;Within the iteration or &lt;strong&gt;for loop&lt;/strong&gt;, specify the index of the content intended to be split, which then gets the content string for every row. After, obtain the ideal size of a chunk through the floor division of a set max &lt;code&gt;idealTokenSize&lt;/code&gt; (512) by &lt;code&gt;1.3&lt;/code&gt; and explicitly convert the subsequent result to an integer.&lt;/p&gt;

&lt;p&gt;Next, split the content string gotten earlier into words using a space delimiter (""), filter a list of words, remove occurrences of the delimiter, and assign the resulting list back to the variable. Then, it gets the length of the new list using the &lt;code&gt;length&lt;/code&gt; method, which is now the total number of words in the content.&lt;/p&gt;

&lt;p&gt;After, it determines the number of chunks needed based on a floor division of the total words by the ideal size of a chunk. The document is split into ideal-sized chunks, and each chunk is added to the &lt;code&gt;chunkList&lt;/code&gt; with an ID that combines the original document's ID and the chunk number.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;splitToChunks method&lt;/code&gt; returns the &lt;code&gt;chunkList&lt;/code&gt;. The &lt;code&gt;splitToChunks&lt;/code&gt; method ensures that each chunk is approximately of the ideal size, but the actual size can vary depending on the word boundaries.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// loadCSV&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitToChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunkList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;idealTokenSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;idealSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idealTokenSize&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/ &lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;4 /&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;idealSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;word&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;totalWords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;totalWords&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/ idealSize&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalWords&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;idealSize&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;newContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;totalWords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;totalWords&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;newContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sublist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;newContentString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;chunkList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${id}_$j&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newContentString&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;idealSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;idealSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chunkList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;To embed the &lt;code&gt;chunkList&lt;/code&gt;, implement the &lt;code&gt;getEmbeddings&lt;/code&gt; method and pass the &lt;code&gt;chunkList&lt;/code&gt; as an input. Here is the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// loadCSV&lt;/span&gt;

  &lt;span class="c1"&gt;// splitToChunks&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Embedding ....&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embeddedDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.openai.com/v1/embeddings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer ${dotenv.env[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;]!}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;jsonEncode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-embedding-ada-002&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;responseData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jsonDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;responseData&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;embedding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embeddingdouble&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;FormatException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid format&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;embeddedDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;embeddingdouble&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Embedding complete....&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;embeddedDoc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;getEmbeddings&lt;/code&gt; method takes the &lt;code&gt;chunkList&lt;/code&gt; list — a list of strings as an input. It will iterate over every list item within the &lt;code&gt;chunkList&lt;/code&gt; list and perform a specific action to create embeddings for them. &lt;/p&gt;

&lt;p&gt;To achieve this, start by initializing an empty list of lists of doubles &lt;code&gt;embeddedDoc&lt;/code&gt; to store the embeddings. Then, use a for loop to iterate over each list item in the &lt;code&gt;chunkList&lt;/code&gt; list while performing the following actions on each iteration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the &lt;code&gt;http&lt;/code&gt; package, make a POST request to the &lt;code&gt;OpenAI API&lt;/code&gt; to get the embedding of a list item from the &lt;code&gt;chunkList&lt;/code&gt; list.&lt;/li&gt;
&lt;li&gt;If the response status is 200, decode the response body to get the embedding, convert it to a list of doubles, and add it to &lt;code&gt;embeddedDoc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the response status is not 200, throw an exception with the response body as the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, let the &lt;code&gt;getEmbeddings&lt;/code&gt; method return &lt;code&gt;embeddedDoc&lt;/code&gt;, a list of embeddings where each embedding is a list of doubles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Store&lt;/strong&gt;&lt;br&gt;
Now, you have a couple of data (&lt;code&gt;chunkList&lt;/code&gt;  and &lt;code&gt;embeddedDoc&lt;/code&gt;) that need storing in someplace, and that is where your Neon database comes in. To store your embedding (&lt;code&gt;embeddedDoc&lt;/code&gt;) and chunks (&lt;code&gt;chunkList&lt;/code&gt;), you must create a database table and enable the pgvector's vector extension in the database. The vector extension is handy as it lets you search using a vector cosine's similarity index when querying the database later.&lt;/p&gt;

&lt;p&gt;Thus, start by updating the &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; abstraction in the &lt;code&gt;lib/home/controller/openai_indexing_services.dart&lt;/code&gt; file with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="nx"&gt;classOpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// the abstraction above&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkExtExist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkTableExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonVecorExt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;deleteNeonTableRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;storeDoument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embeddedVectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Remember, Neon allows database management using SQL commands — equally, you can execute these SQL commands programmatically in Flutter using the &lt;code&gt;Postgres&lt;/code&gt; package. &lt;/p&gt;

&lt;p&gt;Thus, for the implementation in the &lt;code&gt;lib/home/controller/openai_indexing_services_impl.dart&lt;/code&gt;, the &lt;code&gt;checkExtExist&lt;/code&gt;, and &lt;code&gt;checkTableExist&lt;/code&gt; methods are condition checkers that use the &lt;code&gt;SELECT&lt;/code&gt; statement to confirm if the vector extension and a particular table exist within the database. They return boolean values dependent on the result obtained from the request.&lt;/p&gt;

&lt;p&gt;Next, use the &lt;code&gt;createNeonVecorExt&lt;/code&gt; method to create a 'vector' extension in the Neon Postgres database. Also, the &lt;code&gt;createNeonTable&lt;/code&gt; method creates a specified table in the Neon Postgres database with &lt;strong&gt;id&lt;/strong&gt;, &lt;strong&gt;metadata&lt;/strong&gt;, and embedding fields. It also creates an index on the embedding field using the &lt;code&gt;ivfflat&lt;/code&gt; algorithm and vector_cosine_ops operator class. The &lt;code&gt;deleteNeonTableRows&lt;/code&gt; method truncates all rows from a specified table in the Neon Postgre database. &lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;storeDoument&lt;/code&gt; method stores the data in the Neon database table created earlier by iterating over the &lt;code&gt;chunkList&lt;/code&gt; and &lt;code&gt;embeddedDoc&lt;/code&gt;,  inserting the id, &lt;code&gt;metadata&lt;/code&gt;, and &lt;code&gt;embedding&lt;/code&gt; into the table. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;metadata&lt;/code&gt; field is a map containing &lt;code&gt;pageContent&lt;/code&gt; and &lt;code&gt;txtPath&lt;/code&gt; keys, which are the IDs in the &lt;code&gt;chunkList&lt;/code&gt;, while the &lt;code&gt;embedding&lt;/code&gt; field is a string representation of an array of doubles.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// loadCSV&lt;/span&gt;

  &lt;span class="c1"&gt;// splittoChunks&lt;/span&gt;

  &lt;span class="c1"&gt;// getEmbeddings&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkExtExist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;checkExtExist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT EXISTS (SELECT FROM pg_extension WHERE extname = 'vector');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;checkExtExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkTableExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;checkTableExist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT EXISTS (SELECT FROM information_schema.tables WHERE  table_schema = 'public' AND table_name = '$tableName');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;checkTableExist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonVecorExt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Creating pgvector extension ...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CREATE EXTENSION vector;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vector extension created Successfully&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Creating the $tableName table ... &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CREATE TABLE $tableName (id text, metadata text, embedding vector(1536));&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Indexing the $tableName using the ivfflat vector cosine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CREATE INDEX ON $tableName USING ivfflat (embedding vector_cosine_ops) WITH (lists = 24);&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Table created successfully&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;deleteNeonTableRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deleting tableRows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TRUNCATE $tableName;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Table rows deleted successfuly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;storeDoument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embeddedVectors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Storing data... &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runTx&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;embeddingArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;embeddedVectors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;Sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;named&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO $tableName (id, metadata, embedding) VALUES (@id, @metadata, @embedding)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pageContent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;txtPath&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;embedding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$embeddingArray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data stored!!!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;With this, you have successfully indexed the data; the next step is to retrieve it!&lt;/p&gt;
&lt;h2&gt;
  
  
  Retrieval
&lt;/h2&gt;

&lt;p&gt;Retrieval is a streamlined component commonly divided into two processes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve: This is done by comparing the vector embedding of a user query with the closest available result present in the database. We perform this comparison using the cosine similarity search to compare a vector with another. Thus, when you get the closest results, you can use it for the second process.&lt;/li&gt;
&lt;li&gt;Generate: After getting the closest result, you can use it as an LLM assistance to generate responses based on that information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this, head to the &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; abstract class in the &lt;code&gt;lib/home/controller/openai_indexing_services.dart&lt;/code&gt; and update it with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;queryNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The method above returns a string response by following the retrieval process above.&lt;/p&gt;

&lt;p&gt;Here is the code for the implementation of the &lt;code&gt;queryNeonTable&lt;/code&gt; method below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/muyiwexy/6e3318ae0c07802c10f3cabc2450c69d" rel="noopener noreferrer"&gt;openai_indexing_service_impl.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;OpenAIIndexingServicesImpl&lt;/code&gt; class in the code above, you must define a method &lt;code&gt;getCompletionFromMessages&lt;/code&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes a POST request to the OpenAI API to get a completion from a list of messages.&lt;/li&gt;
&lt;li&gt;If the response status is 200, it decodes the response body to get the completed content.&lt;/li&gt;
&lt;li&gt;If the response status is not 200, it throws an exception with the response body as the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, define a method &lt;code&gt;getQueryEmbeddings&lt;/code&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes a POST request to the OpenAI API to get the embedding of a query.&lt;/li&gt;
&lt;li&gt;If the response status is 200, it decodes the response body to get the embedding, converts it to a list of doubles, and returns it.&lt;/li&gt;
&lt;li&gt;If the response status is not 200, it throws an exception with the response body as the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, use the &lt;code&gt;queryNeonTable&lt;/code&gt; method to get the embedding of a query by calling the &lt;code&gt;getQueryEmbeddings&lt;/code&gt; method. Afterward, execute an SQL query on the &lt;code&gt;connection&lt;/code&gt; using &lt;code&gt;Postgres&lt;/code&gt; to get similar items from a specified table. After getting a list of similar items from the table, convert the result into a list of &lt;code&gt;Metadata&lt;/code&gt; objects.&lt;/p&gt;

&lt;p&gt;Add a condition to check if &lt;code&gt;Metadata&lt;/code&gt; is not empty, and if valid, concatenate the page content, make a list of messages, get a completion from the messages, and return it. If &lt;code&gt;Metadata&lt;/code&gt; is empty, it returns a default message: "Couldn't find anything on that topic."&lt;/p&gt;

&lt;p&gt;Here is the &lt;code&gt;Metadata&lt;/code&gt; objects model class below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;txtPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txtPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;factory&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageContent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nx"&gt;txtPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;txtPath&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageContent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;txtPath&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;txtPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Save it in the &lt;code&gt;lib/home/model/&lt;/code&gt; directory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Handling the abstraction, state management, and dependency injection
&lt;/h2&gt;

&lt;p&gt;Though you have created and implemented functionalities that encapsulate the idea of this project, it is still all business logic. This means there is no connection between the business logic and the presentation layer (UI). To implement this connection, there will need to be a "handshake" between these layers, and you can do this by creating a class that will have direct contact with the presentation layer.&lt;/p&gt;

&lt;p&gt;To begin, create a new directory called &lt;code&gt;view_model&lt;/code&gt; in the &lt;code&gt;lib/home/&lt;/code&gt; folder, this folder will have two files to handle indexing and retrieval, respectively. Create a file in the &lt;code&gt;lib/home/view_model/&lt;/code&gt; directory called &lt;code&gt;index_notifier.dart&lt;/code&gt;. This file will cater to the indexing processes established earlier and the application's state involved in the process. &lt;/p&gt;

&lt;p&gt;The project will explore a simple management solution called &lt;code&gt;ValueNotifiers&lt;/code&gt;for state management. This is mainly down to the fact that you aren't dealing with a complex.&lt;br&gt;
UI and might be listening to single values throughout the project.&lt;/p&gt;

&lt;p&gt;So, start by creating an &lt;code&gt;enum&lt;/code&gt; class within the &lt;code&gt;lib/home/view_model/index_notifier.dart&lt;/code&gt; file with &lt;code&gt;initial, loading, loaded, and error values&lt;/code&gt; to track the application’s state. Then, create an &lt;code&gt;IndexNotifier&lt;/code&gt; class and instantiate the &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; object from the &lt;code&gt;lib/home/controller/openai_indexing_services.dart&lt;/code&gt;. Make sure to pass in the &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; object to the constructor.&lt;/p&gt;

&lt;p&gt;Next, define a &lt;code&gt;ValueNotifier&lt;/code&gt;, for &lt;code&gt;indexState&lt;/code&gt; to track the state of the indexing process, followed by creating a method &lt;code&gt;indexingNeonTable&lt;/code&gt;. The &lt;code&gt;indexingNeonTable&lt;/code&gt; does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets &lt;code&gt;indexState&lt;/code&gt; to &lt;code&gt;loading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Loads a CSV document using &lt;code&gt;openAIIndexingServices&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Splits the document into chunks and gets their embeddings.&lt;/li&gt;
&lt;li&gt;Check if the 'vector' extension exists in the database and create it if not.&lt;/li&gt;
&lt;li&gt;Check if a specified table exists in the database and create it if not. If the table already exists, it deletes all rows from the table.&lt;/li&gt;
&lt;li&gt;Stores the chunks and their embeddings in the table.&lt;/li&gt;
&lt;li&gt;Sets &lt;code&gt;indexState&lt;/code&gt; to &lt;code&gt;loaded&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Handles errors by setting &lt;code&gt;indexState&lt;/code&gt; to &lt;code&gt;error&lt;/code&gt; and rethrowing the exception.&lt;/li&gt;
&lt;li&gt;After a delay, set &lt;code&gt;indexState&lt;/code&gt; to &lt;code&gt;initial&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the code in the &lt;code&gt;index_notifier.dart&lt;/code&gt; below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;IndexState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;_indexState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;indexState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_indexState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;indexingNeonTable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_indexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;csvDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadCSV&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitToChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;csvDoc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;embeddedDocs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkExtExist&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNeonVecorExt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkTableExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ServiceConfigurations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAITable&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ServiceConfigurations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAITable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteNeonTableRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ServiceConfigurations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAITable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;storeDoument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;embeddedDocs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;ServiceConfigurations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAITable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;_indexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_indexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;_indexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;IndexState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Create another file within the &lt;code&gt;lib/home/view_model&lt;/code&gt; called &lt;code&gt;query_notifier.dart&lt;/code&gt;for the second file. This file does similarly to the &lt;code&gt;index_notifier.dart&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;Begin by creating a &lt;code&gt;Message&lt;/code&gt; model class with String values &lt;code&gt;query&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; and pass them into the constructor. Also, create an &lt;code&gt;enum&lt;/code&gt; class within the file with values &lt;code&gt;initial, loading, loaded, error&lt;/code&gt; to track the state of the application when a user queries the LLM.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;QueryNotifier&lt;/code&gt; class that initializes the &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; object from the &lt;code&gt;lib/home/controller/openai_indexing_services.dart&lt;/code&gt;, followed by defining a &lt;code&gt;ValueNotifier&lt;/code&gt; for &lt;code&gt;_queryandResponseState&lt;/code&gt; to track the state of the query and response.&lt;/p&gt;

&lt;p&gt;After, define a &lt;code&gt;ValueNotifier&lt;/code&gt; for &lt;code&gt;queryState&lt;/code&gt; to track the state of the query. Follow this by creating a method &lt;code&gt;queryIngeonTable&lt;/code&gt; that does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adds a new &lt;code&gt;Message&lt;/code&gt; to &lt;code&gt;_messages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Sets &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;loading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;queryNeonTable&lt;/code&gt; method of &lt;code&gt;openAIIndexingServices&lt;/code&gt; to get a response.&lt;/li&gt;
&lt;li&gt;Updates the last message's response and sets &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;loaded&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Handles errors by setting &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;error&lt;/code&gt;, then back to &lt;code&gt;initial&lt;/code&gt; after a delay.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueryandResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;QueryandResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;OpenAIIndexingServices&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryandResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_queryandResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;_queryandResponseState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryandResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryandResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;queryandResponseState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;_queryandResponseState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;_queryState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;queryState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;queryIngeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_queryandResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;QueryandResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

      &lt;span class="nx"&gt;_queryandResponseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_queryandResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;ServiceConfigurations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openAITable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryandResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_queryandResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;updatedMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;_queryandResponseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;updatedMessages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle errors if necessary&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;With that, a "handshake" is possible but not yet established, as the Flutter application is unaware of a few things, such as where/what the &lt;strong&gt;Postgres connection&lt;/strong&gt; is established. This is because the Postgres connection is a required field of the &lt;code&gt;OpenAIIndexingServicesImpl&lt;/code&gt; class in the &lt;code&gt;lib/home/controller/openai_indexing_services_impl.dart&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;Thus, the next section will clarify how to mount dependencies on the widget tree and connect Flutter to the neon database. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Check out the &lt;code&gt;lib/core/dependency_injection/provider_locator.dart&lt;/code&gt; file to see how to inject the objects as a dependency using the &lt;code&gt;provider&lt;/code&gt; package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Connecting Neon database to Flutter application and dependency injection&lt;/strong&gt;&lt;br&gt;
 You used the &lt;code&gt;Postgres&lt;/code&gt; package to execute SQL commands during this project. The &lt;code&gt;Postgres&lt;/code&gt; package also connects the Flutter app to the Neon database to facilitate the execution of those commands declared in your code. The code containing the connection process is in the &lt;code&gt;provider_locator.dart&lt;/code&gt; file from the template. &lt;/p&gt;

&lt;p&gt;Here is the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProviderLocator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// provider tree&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MultiProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_createOpenAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MultiProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OpenAIIndexingServices&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;openAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openAIIndexingService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OpenAIIndexingServices&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;_createOpenAIIndexingServices&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPostgresConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_createHtttpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;OpenAIIndexingServicesImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// postgres connection&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createPostgresConnection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PGHOST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PGDATABASE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PGUSER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ConnectionSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;sslMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SslMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verifyFull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;connectTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connection Established!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kDebugMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error creating PostgreSQL connection: $e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// If maxRetries is reached and the connection is still not open, throw an exception&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to establish a PostgreSQL connection after $maxRetries retries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;_createHtttpClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In the code above, the &lt;code&gt;ProviderLocator&lt;/code&gt; class in the code does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines a method &lt;code&gt;getProvider&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Creates an &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Returns a &lt;code&gt;MultiProvider&lt;/code&gt; with an &lt;code&gt;OpenAIIndexingServices&lt;/code&gt; provider and two other providers for &lt;code&gt;IndexNotifier&lt;/code&gt; and &lt;code&gt;QueryNotifier&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Defines a method &lt;code&gt;_createOpenAIIndexingServices&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Creates a PostgreSQL connection using the connection details from the Neon database.&lt;/li&gt;
&lt;li&gt;Creates an HTTP client.&lt;/li&gt;
&lt;li&gt;Returns an &lt;code&gt;OpenAIIndexingServicesImpl&lt;/code&gt; instance with the created connection and client.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Defines a method &lt;code&gt;createPostgresConnection&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Tries to establish a PostgreSQL connection with specified settings.&lt;/li&gt;
&lt;li&gt;If the connection fails, it retries up to a maximum number of times.&lt;/li&gt;
&lt;li&gt;If the connection is not established after maximum retries, it throws an exception.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Defines a method &lt;code&gt;_createHtttpClient&lt;/code&gt; that returns an HTTP client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that, you have successfully mounted the database on the widget tree and established a connection between the Neon Postgres database and Flutter. When you run the application, you should have your results as shown in the video below:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://app.opentape.io/share/e2e7adb7-e378-45d4-8aa9-0a1054149571" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapp.opentape.io%2Fthumbnail%2Fe2e7adb7-e378-45d4-8aa9-0a1054149571" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://app.opentape.io/share/e2e7adb7-e378-45d4-8aa9-0a1054149571" rel="noopener noreferrer" class="c-link"&gt;
          rag with openai | Opentape
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Muyiwa Femi-Ige - Feb 21st, 10:32am
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapp.opentape.io%2Ffavicon.ico"&gt;
        app.opentape.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_964690F313FCB7BF5A8DA8AD61B7B343BE4D8FEC3CDDBE5C5F7F48C77A8E4E9B_1701382149450_rag_openai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_964690F313FCB7BF5A8DA8AD61B7B343BE4D8FEC3CDDBE5C5F7F48C77A8E4E9B_1701382149450_rag_openai.png" alt="neon database result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This tutorial journeyed into the world of RAG and its implementation in mobile applications using the Flutter framework, Neon Postgres, and OpenAI. It explored how RAG enhances the response capabilities of LLMs by providing them with an external knowledge source.&lt;/p&gt;

&lt;p&gt;You also learned about Neon and its capabilities with the pgvector extension. If you’ve gotten this far, you’re now equipped with the knowledge to build more intelligent and responsive applications using RAG, opening up new possibilities in AI.&lt;/p&gt;

&lt;p&gt;If this piqued your curiosity, let's contribute to advancing AI, making it more accessible, efficient, and beneficial for all. Happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Here are some resources that will guide you more in this journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt; &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python.langchain.com/docs/use_cases/question_answering/" rel="noopener noreferrer"&gt;Retrieval-augmented generation (RAG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.openai.com/t/vector-similarity-search-in-postgres-with-pgvector-text-embedding-ada-002-and-bit-io/150558" rel="noopener noreferrer"&gt;Vector Similarity Search in Postgres with pgvector, text-embedding-ada-002, and bit.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=y2va_4m9FLQ" rel="noopener noreferrer"&gt;H&lt;/a&gt;&lt;a href="https://www.youtube.com/watch?v=y2va_4m9FLQ" rel="noopener noreferrer"&gt;ow to build a PDF.ai clone with Flutter, Pinecone Vector Database, Langchain, and ChatGPT without any backend or Python.&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openai</category>
      <category>tutorial</category>
      <category>mobile</category>
      <category>flutter</category>
    </item>
    <item>
      <title>How to set up Auth0 and Neon Postgres in Next.js App Router</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Tue, 13 Feb 2024 09:34:54 +0000</pubDate>
      <link>https://dev.to/hackmamba/how-to-set-up-auth0-and-neon-postgres-in-nextjs-app-router-48ad</link>
      <guid>https://dev.to/hackmamba/how-to-set-up-auth0-and-neon-postgres-in-nextjs-app-router-48ad</guid>
      <description>&lt;p&gt;Modern applications demand a balance of scalability, speed, and security to meet users’ ever-growing needs. Ensuring authentication and a robust database management system is crucial at the foundation of this triad. In this article, we’ll talk about the combination of Auth0 and Neon Postgres when you need to accommodate these two needs.&lt;/p&gt;

&lt;p&gt;Auth0 is an identity platform that simplifies authentication and authorization functionalities across web, mobile, and native applications.&lt;/p&gt;

&lt;p&gt;Neon is fully managed serverless Postgres that provides separate storage and computing to offer autoscaling, branching, and bottomless storage. Neon is open source under the Apache 2.0 licenses; you can check out the &lt;a href="https://github.com/neondatabase/neon?ref=hm"&gt;neondatabase&lt;/a&gt; GitHub repo.&lt;/p&gt;

&lt;p&gt;This guide provides a comprehensive walk-through of setting up Auth0 with a Postgres database like Neon by building a login page that routes to a profile page while implementing Neon Postgres as the data store for user information. This application uses the Next.js React framework with App Router and Tailwind for styling.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here is the link to the GitHub &lt;a href="https://github.com/muyiwexy/auth_postgres?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity"&gt;repository&lt;/a&gt; containing all the code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To successfully complete this guide, you’ll need a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proficiency with JavaScript frameworks such as &lt;a href="https://nextjs.org/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity"&gt;Next.js&lt;/a&gt; (&lt;strong&gt;recommended&lt;/strong&gt;), React, etc.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://console.neon.tech/sign_in"&gt;Neon account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://auth0.com/signup?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity"&gt;Auth0 account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download"&gt;Node 18&lt;/a&gt; or later versions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up a Neon Postgres project
&lt;/h2&gt;

&lt;p&gt;After signing up, you’ll note Neon's streamlined project setup; you’ll just need to provide three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project name&lt;/li&gt;
&lt;li&gt;Postgres version&lt;/li&gt;
&lt;li&gt;Database name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the project setup page, there are more options to explore; for example, you can change the branch name to any other name, but we recommend leaving it as &lt;code&gt;main&lt;/code&gt; for now. Next, click &lt;strong&gt;Create project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fAw4OsXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fAw4OsXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" alt="Neon sign-in" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--phIIdadc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--phIIdadc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" alt="Create project" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OjonCln3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OjonCln3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" alt="More options" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the homepage, you'll find a popup containing all the connection details required to connect your application(s) to a Neon database. Copy these details to a safe file, such as a JSON file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YUAxdjFT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YUAxdjFT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" alt="Connection details" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Next.js application and installing dependencies
&lt;/h2&gt;

&lt;p&gt;To create a Next.js application, open your terminal in any folder of your choice and type the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;latest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command creates a Next.js application with TypeScript as the preferred programming language.&lt;/p&gt;

&lt;p&gt;Next, we need to install some dependencies. These include an Auth0 dependency and &lt;code&gt;dotenv&lt;/code&gt; to store sensitive credentials in a &lt;code&gt;.env&lt;/code&gt; file. To do this, run the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;auth0&lt;/span&gt;&lt;span class="sr"&gt;/nextjs-auth0 doten&lt;/span&gt;&lt;span class="err"&gt;v
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Configuring Auth0 application settings
&lt;/h2&gt;

&lt;p&gt;After signing into the Auth0 account you created earlier, click &lt;strong&gt;Create Application&lt;/strong&gt; in the Auth0 dashboard, select &lt;strong&gt;Regular Web Applications,&lt;/strong&gt; and fill in the &lt;strong&gt;app name&lt;/strong&gt; to create traditional web applications that use redirects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FbExYoGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702995071772_new.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FbExYoGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702995071772_new.png" alt="dashboard" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d4DYPz-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702681964913_regular%2Bweb%2Bapplication.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d4DYPz-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702681964913_regular%2Bweb%2Bapplication.png" alt="Regular web application" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following prompt asks what technology is being used for the project; we’ll select Next.js out of all the presented options for this project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U0XRyIMw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702682229341_technology.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U0XRyIMw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702682229341_technology.png" alt="Technology" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over at your just-created &lt;strong&gt;Regular Web Applications&lt;/strong&gt;, you’ll need to configure the URLs for your app under the application URI. To do this, head to &lt;strong&gt;Settings &amp;gt; Allowed Callback URLs&lt;/strong&gt; and type in the URL below within the input field:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000/api/auth/callback&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, we use port &lt;code&gt;3000&lt;/code&gt; as the port our application runs on, so make sure to select the port your application is running on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: you can add multiple URLs by separating them with a comma ","&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The URL above completes the web application's authentication flow by triggering the &lt;code&gt;callback&lt;/code&gt; route after successful authentication. The callback route &lt;code&gt;api/auth/callback&lt;/code&gt; is integrated by Auth0 into the &lt;code&gt;@auth0/nextjs-auth0&lt;/code&gt; package installed earlier, which will handle the callback flow.&lt;/p&gt;

&lt;p&gt;Next, we’ll add the following URL in the &lt;strong&gt;Allowed Logout URLs&lt;/strong&gt; input field:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Setting this allows a redirect back to our web application after logging out, and you can use a personal URL if your project requires it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WPKCSk3F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702721836991_application%2BURIs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WPKCSk3F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702721836991_application%2BURIs.png" alt="Allowed callbacks" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you're done with that, save the changes and head to the top page of the &lt;strong&gt;Settings&lt;/strong&gt; section. Make sure to note the &lt;strong&gt;Domain, Client ID, and Secret,&lt;/strong&gt; as they will come in handy in the coming sections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNcHJYoh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702721836953_basic%2Binformation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNcHJYoh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702721836953_basic%2Binformation.png" alt="Basic information" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Connecting NextJs to Auth0
&lt;/h2&gt;

&lt;p&gt;To initiate a connection between Auth0 and Next.js, head back to the Next.js application we created and create a &lt;code&gt;.env.local&lt;/code&gt; file in the root folder to store the &lt;strong&gt;Domain, Client ID, and Secret&lt;/strong&gt; from Auth0. Then, paste the following variables into the file below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;AUTH0_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;openssl&lt;/span&gt; &lt;span class="nx"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="nx"&gt;AUTH0_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:3000&lt;/span&gt;
&lt;span class="nx"&gt;AUTH0_ISSUER_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//AUTH0-DOMAIN&lt;/span&gt;
&lt;span class="nx"&gt;AUTH0_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AUTH0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;CLIENT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;
&lt;span class="nx"&gt;AUTH0_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AUTH0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;CLIENT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;SECRET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: You can get these pages from &lt;a href="https://auth0.com/docs/quickstart/webapp/nextjs/01-login?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity"&gt;Auth0's Nextjs documentation&lt;/a&gt; and replace the values with those of your Auth0 regular web app's values.mk&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will need to generate a 32-byte random value for the &lt;code&gt;AUTH0_SECRET&lt;/code&gt;, and this can be done using Node's &lt;code&gt;crypto&lt;/code&gt; module. The &lt;code&gt;crypto&lt;/code&gt; module generates an arbitrary hexadecimal string of length 32. Thus, head to your terminal and type the command below to use the module:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;console.log(crypto.randomBytes(32).toString('hex'))&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Creating an API route for Auth0
&lt;/h2&gt;

&lt;p&gt;Next, we'll need to add the dynamic API route; we’ll do so by creating a &lt;code&gt;/api&lt;/code&gt; directory within the &lt;code&gt;/app&lt;/code&gt; directory. Within the now &lt;code&gt;/app/api&lt;/code&gt; directory, create an &lt;code&gt;/auth&lt;/code&gt; directory to handle all the authentication-related things within this project (create this directory instead if you already have an &lt;code&gt;/api&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;/auth&lt;/code&gt; directory, create a new unique directory called &lt;code&gt;/[auth0]&lt;/code&gt; and create a file &lt;code&gt;route.tsx&lt;/code&gt; within the folder. Using a directory in this manner, &lt;code&gt;/[auth0] indicates&lt;/code&gt; that the directory name &lt;strong&gt;auth&lt;/strong&gt; is a dynamic segment.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;route.tsx&lt;/code&gt; file, we will use the &lt;code&gt;handleAuth&lt;/code&gt; method from the &lt;code&gt;@auth0/nextjs-auth0&lt;/code&gt; to handle the authentication flow of our web application. The &lt;code&gt;handleAuth&lt;/code&gt; creates multiple route handlers under the hood — this means that when we log initially into Auth0, the routes followed are &lt;strong&gt;api-auth-login.&lt;/strong&gt; So, the &lt;code&gt;handleAuth&lt;/code&gt; function will handle all the login flow based on that and log out the callback URLs set earlier.&lt;/p&gt;

&lt;p&gt;So, let’s add the code below to the &lt;code&gt;route.tsx&lt;/code&gt; to implement what we just explained above:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handleAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/nextjs-auth0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handleAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we need to wrap our application in an Auth0 &lt;code&gt;UserProvider&lt;/code&gt;. In the &lt;code&gt;layout.tsx&lt;/code&gt; file from the base &lt;code&gt;/app&lt;/code&gt; directory, we’ll import &lt;code&gt;UserProvider&lt;/code&gt; from &lt;code&gt;@auth0/nextjs-auth0/client&lt;/code&gt;, and then we'll wrap the body tag in a &lt;code&gt;UserProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So here is the updated &lt;code&gt;layout.tsx&lt;/code&gt; file below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./globals.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/nextjs-auth0/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Auth0 and Neon Postgres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Generated by create next app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/UserProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We perform this operation using an Auth0 platform to create and authenticate users. Therefore, we will have to wrap our entire application in Auth0. At the moment, these are all the configurations needed for our web application. In the coming sections, we will create pages for logging in and a profile page to display certain user information.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the pages and routes using Next.js and Auth0
&lt;/h2&gt;

&lt;p&gt;This project will use the initial page (&lt;code&gt;/app/page.tsx&lt;/code&gt;) and profile routes. The initial page route will be a form with email, password input, and a submit button. Also, there will be a button that triggers a connection to Auth0. For the profile area, a simple card will show the user's profile image, name, and email. The card will also contain a logout button that triggers a logout action from Auth0.&lt;/p&gt;

&lt;p&gt;The idea is to give a clearer picture of how the &lt;strong&gt;App Router&lt;/strong&gt; operates after successful authentication with Auth0. Earlier, we enabled &lt;strong&gt;App Router&lt;/strong&gt; when we created our project — thus, route by creating another folder in the &lt;code&gt;/app&lt;/code&gt; directory, let's call it &lt;code&gt;profile&lt;/code&gt;. Within this &lt;code&gt;profile&lt;/code&gt; directory, create a file called &lt;code&gt;page.tsx&lt;/code&gt;. With that, you've successfully created a route with &lt;strong&gt;App Router.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Head back to the &lt;code&gt;/app/page.tsx&lt;/code&gt; file, clear out the initial template, and replace it with the one below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex min-h-screen items-center justify-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-[300px] md:w-[600px] shadow-lg p-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-5xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;E-mail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black w-full p-5 text-2xl rounded-lg focus:outline-blue-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black w-full p-5 text-2xl rounded-lg focus:outline-blue-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[40px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex justify-end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black p-5 px-10 text-2xl rounded-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nx"&gt;Try&lt;/span&gt; &lt;span class="nx"&gt;Me&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex justify-center font-bold text-2xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Or&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 w-full border-black p-5 px-10 text-2xl rounded-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;Auth0&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The code above is the login UI template mentioned earlier, and when we run the code, our application will look like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ebGNCzA0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702846631032_nextjs%2Blogin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ebGNCzA0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702846631032_nextjs%2Blogin.png" alt="Login template" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still within the &lt;code&gt;/app/pages.tsx&lt;/code&gt; file, import &lt;code&gt;useUser&lt;/code&gt; function from &lt;code&gt;@auth0/nextjs-auth0/client&lt;/code&gt;. Then return &lt;code&gt;user, error, isLoading&lt;/code&gt; from the &lt;code&gt;useUser&lt;/code&gt; function in the &lt;code&gt;Login&lt;/code&gt; function. The &lt;code&gt;user&lt;/code&gt; object allows us to display user information after a successful login. In this case, where we experience any errors during signups or login, the &lt;code&gt;error&lt;/code&gt; object will display the error message. &lt;code&gt;isLoading&lt;/code&gt; is a Boolean parameter that lets us know when data is being loaded.&lt;/p&gt;

&lt;p&gt;Also, we will use Next.js navigation to handle navigation using the &lt;code&gt;useRouter&lt;/code&gt; function. To do this, we’ll import the &lt;code&gt;useRouter&lt;/code&gt; function from &lt;code&gt;next/navigation,&lt;/code&gt; then return &lt;code&gt;push&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this, we can use a condition to check if there is a &lt;code&gt;user&lt;/code&gt; object, and if it is true, push it to the &lt;code&gt;/profile&lt;/code&gt; route created earlier. Also, we will use the &lt;code&gt;useRouter&lt;/code&gt; function to create a login link that will allow us to sign up and log in to our Auth0 application.&lt;/p&gt;

&lt;p&gt;First, create a function that pushes to the route &lt;code&gt;api/auth/login&lt;/code&gt; and set an &lt;code&gt;onClick&lt;/code&gt; event to the function in the &lt;code&gt;Sign in with Auth0&lt;/code&gt; button from our template code.&lt;/p&gt;

&lt;p&gt;Below is the updated code for the &lt;code&gt;page.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/nextjs-auth0/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api/auth/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex min-h-screen items-center justify-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-[300px] md:w-[600px] shadow-lg p-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-5xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;E-mail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black w-full p-5 text-2xl rounded-lg focus:outline-blue-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black w-full p-5 text-2xl rounded-lg focus:outline-blue-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[40px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex justify-end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black p-5 px-10 text-2xl rounded-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nx"&gt;Try&lt;/span&gt; &lt;span class="nx"&gt;Me&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex justify-center font-bold text-2xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Or&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[20px]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
          &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLogin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 w-full border-black p-5 px-10 text-2xl rounded-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;Auth0&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you click the button above, an Auth0 login will be created successfully, but the objective is incomplete as there is currently nothing to display in the &lt;code&gt;/profile/page.tsx&lt;/code&gt;. So, we’ll add a UI template code that contains a user image area, name, email, and a logout button.&lt;/p&gt;

&lt;p&gt;Thus, head to the &lt;code&gt;/profile/page.tsx&lt;/code&gt; file and paste the template code below to it:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-[1900px] flex flex-col mx-auto mt-5 rounded-2xl overflow-hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[250px] bg-black relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[150px] w-[150px] rounded-full border-2 bg-gray-600 absolute -bottom-[75px] z-50 left-10 overflow-hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
            &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;picture&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default-image-url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object-cover h-full, w-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[300px] relative transl bg-slate-600 p-5 flex justify-between&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-[90px] text-3xl font-bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-[20px] text-2xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default-email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black p-5 px-10 text-2xl rounded-lg cursor-pointer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Log&lt;/span&gt; &lt;span class="nx"&gt;Out&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When we run the code, the &lt;code&gt;/profile&lt;/code&gt; route should look like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9kISLWbd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702851241542_profile%2Bpage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9kISLWbd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702851241542_profile%2Bpage.png" alt="Profile template" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still within the &lt;code&gt;/app/profile/page.tsx&lt;/code&gt; file, we'll do similarly to what we did in the &lt;code&gt;/app/pages.tsx&lt;/code&gt; file with a slight twist. Start by importing the &lt;code&gt;useUser&lt;/code&gt; function and the &lt;code&gt;withPageAuthRequired&lt;/code&gt; function from &lt;code&gt;@auth0/nextjs-auth0/client&lt;/code&gt;. Then return &lt;code&gt;user, error, isLoading&lt;/code&gt; from the &lt;code&gt;useUser&lt;/code&gt; function in the &lt;code&gt;Profile&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Next, use the &lt;code&gt;useRouter&lt;/code&gt; function to create a logout link to allow us to log out of our Auth0 application. To do this, create a function that pushes to the route &lt;code&gt;api/auth/logout&lt;/code&gt; and set an &lt;code&gt;onClick&lt;/code&gt; event to the function in the &lt;code&gt;Log Out&lt;/code&gt; button from the &lt;code&gt;/profile&lt;/code&gt; route template code.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;withPageAuthRequired&lt;/code&gt; is a higher-order component used to protect pages requiring authentication. So, we will need to wrap the &lt;code&gt;Profile&lt;/code&gt; function with a map object that contains properties &lt;code&gt;onRedirecting&lt;/code&gt; and &lt;code&gt;onError&lt;/code&gt; that shows specific messages per the context.&lt;/p&gt;

&lt;p&gt;Here is the updated code to the &lt;code&gt;/app/profile/page.tsx&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;withPageAuthRequired&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/nextjs-auth0/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// arrow function that routes to the logout api from the [handleAuth] method&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleLogout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api/auth/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// handle isLoading state from Auth0&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// handle error state from Auth0&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// main profile pagelayout&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-[1900px] flex flex-col mx-auto mt-5 rounded-2xl overflow-hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[250px] bg-black relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[150px] w-[150px] rounded-full border-2 bg-gray-600 absolute -bottom-[75px] z-50 left-10 overflow-hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
            &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;picture&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default-image-url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object-cover h-full, w-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-[300px] relative transl bg-slate-600 p-5 flex justify-between&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-[90px] text-3xl font-bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-[20px] text-2xl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
            &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleLogout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-2 border-black p-5 px-10 text-2xl rounded-lg cursor-pointer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Log&lt;/span&gt; &lt;span class="nx"&gt;Out&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;withPageAuthRequired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;onRedirecting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Redirecting&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="p"&gt;....&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;  &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With this, we have reached a milestone, as when we run our application with the command &lt;code&gt;npm run dev&lt;/code&gt;, we can authenticate our application using Auth0.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://app.opentape.io/share/6d311a32-a0de-46d9-ad32-6a69ba1c88b3" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6kVvezl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://app.opentape.io/thumbnail/6d311a32-a0de-46d9-ad32-6a69ba1c88b3" height="450" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://app.opentape.io/share/6d311a32-a0de-46d9-ad32-6a69ba1c88b3" rel="noopener noreferrer" class="c-link"&gt;
          auth0 next js | Opentape
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Muyiwa Femi-Ige - Feb 13th, 9:26am
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A3Ru0yFo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://app.opentape.io/favicon.ico" width="32" height="32"&gt;
        app.opentape.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You’re likely wondering where this data is stored after logging in or signing up. Auth0 utilizes its database to store the data, but we'd like to change that by implementing Auth0 with a custom database — in this case, Neon Postgres. This process ensures user data is available in the primary data store (Neon) for other application development purposes.&lt;/p&gt;

&lt;p&gt;The next section demonstrates how to use Neon as a custom database and sets up some database action scripts for direct communication between Auth0 and Neon Postgres. Let’s jump in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Neon as a custom database on Auth0
&lt;/h2&gt;

&lt;p&gt;Head back to your Auth0 dashboard, and from there, select &lt;strong&gt;Authentication → Database.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4S2Id5X9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702974865301_database.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4S2Id5X9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702974865301_database.png" alt="database" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Database section, create a database connection by clicking Create DB Connection, fill in your desired Connection name, and click &lt;strong&gt;Create.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WaP2wosu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702974693014_create%2Bdb%2Bconnection.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WaP2wosu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702974693014_create%2Bdb%2Bconnection.png" alt="database connection" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wMNXoq6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702975111735_db%2Bconnection%2Bname.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wMNXoq6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702975111735_db%2Bconnection%2Bname.png" alt="database connection name" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your newly created connection, head to the &lt;strong&gt;Custom Database&lt;/strong&gt; section, where all the actions will take place. Toggle the &lt;strong&gt;Use my own database&lt;/strong&gt; option and scroll to the &lt;strong&gt;Database Action Scripts&lt;/strong&gt; area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LGc9uxDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702998959712_custom%2Bdatabase.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LGc9uxDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702998959712_custom%2Bdatabase.png" alt="custom database" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dmUaZqUT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702854979465_DAS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dmUaZqUT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702854979465_DAS.png" alt="DAS" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Database Action Scripts&lt;/strong&gt; section, we can create custom serverless scripts that perform specific actions on our database. The &lt;strong&gt;Login&lt;/strong&gt; script is mandatory; you can set the others as you please. For this tutorial, we will create templates for the six scripts in the image above, and here is their code below in succession:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Login script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script is executed during each login to validate the user's authenticity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT id, nickname, email, password FROM users WHERE email = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WrongUsernameOrPasswordError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WrongUsernameOrPasswordError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script is executed after a user signs up. A database table row is created for the user with the information filled in during the signup process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO users(nickname, email, password) VALUES ($1, $2, $3)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashedPassword&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script verifies the email verification status of a user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE users SET email_verified = true WHERE email_verified = false AND email = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Change password script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script changes the user's encrypted password on the database after following the &lt;strong&gt;change password&lt;/strong&gt; during a password reset process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;changePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bcrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE users SET password = $1 WHERE email = $2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Get user script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This script tests if a user exists in a database. For example, a scenario in which the user wants to change their password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loginByEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT id, nickname, email FROM users WHERE email = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Delete script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This Script is activated when the user is deleted from Auth0 — thus, the user data is subsequently removed from the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POSTGRES_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: With Neon, you can manage your database using a few options, such as a &lt;a href="https://neon.tech/docs/reference/cli-databases?ref=hm"&gt;Command Line Interface (CLI)&lt;/a&gt;, the &lt;a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api?ref=hm"&gt;Neon API&lt;/a&gt;, or a &lt;a href="https://neon.tech/docs/get-started-with-neon/query-with-neon-sql-editor?ref=hm"&gt;Structured Query Language (SQL)&lt;/a&gt; tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After updating the &lt;strong&gt;Database Action Scripts,&lt;/strong&gt; update your &lt;strong&gt;Database settings&lt;/strong&gt; with some sensitive information you used to validate the scripts. For this tutorial, we used the Neon Postgres pooled connection URL.&lt;/p&gt;

&lt;p&gt;To get this URL, head back to your Neon dashboard and copy out the Connection String from the connection detail area. Ensure to mark &lt;strong&gt;Pooled Connection&lt;/strong&gt; as true before copying the details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nlhSx6Ph--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702856218524_Neon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nlhSx6Ph--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702856218524_Neon.png" alt="connection detail" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back in Auth0's &lt;strong&gt;Database settings&lt;/strong&gt; area, create a key with the name &lt;code&gt;POSTGRES_URL&lt;/code&gt; and value with the &lt;strong&gt;Pooled Connection&lt;/strong&gt; string copied from Neon Postgres.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--02l4F-UW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702856510033_database%2Bsettings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--02l4F-UW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702856510033_database%2Bsettings.png" alt="Database settings" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still within your Auth0 &lt;strong&gt;Database Connection,&lt;/strong&gt; head to &lt;strong&gt;Applications&lt;/strong&gt; and toggle on the &lt;strong&gt;Regular Web Applications&lt;/strong&gt;. We have successfully set Neon Postgres as a custom database for our Auth0 application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZuuLMtJA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702975320200_applications.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZuuLMtJA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702975320200_applications.png" alt="applications" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating &lt;code&gt;users&lt;/code&gt; database table on Neon
&lt;/h2&gt;

&lt;p&gt;With the project all but done, there is one tiny thing to add: creating the table for the user store. When creating the &lt;strong&gt;Database Action Script,&lt;/strong&gt; we specified that we are querying a table called &lt;code&gt;users&lt;/code&gt;, so let’s make that our table name.&lt;/p&gt;

&lt;p&gt;For our table, we will create five fields: &lt;strong&gt;id, nickname, email, password, and email_verified.&lt;/strong&gt; So, head to the &lt;a href="https://console.neon.tech/app/projects/divine-sun-12551123/query"&gt;SQL Editor&lt;/a&gt; in Neon's console and run the query below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"uuid-ossp"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;uuid_generate_v4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;nickname&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email_Verified&lt;/span&gt; &lt;span class="nb"&gt;BOOLEAN&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query above creates a UUID column with a default value generated by &lt;code&gt;uuid_generate_v4()&lt;/code&gt; function. It is followed by creating a &lt;code&gt;nickname&lt;/code&gt; column — a variable character (&lt;strong&gt;varchar&lt;/strong&gt;) column with a maximum length of 255 characters.&lt;/p&gt;

&lt;p&gt;Also, it creates an &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; column, a non-null &lt;strong&gt;varchar&lt;/strong&gt; column with a maximum length of 255 characters, and a unique constraint.&lt;/p&gt;

&lt;p&gt;Finally, it creates an &lt;code&gt;email_Verified&lt;/code&gt; column, a &lt;strong&gt;Boolean&lt;/strong&gt; column with a default value of &lt;strong&gt;false&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When we initialize a signup flow with Auth0, here’s the result on the Neon Postgres database table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_noLcIEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702860058717_neon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_noLcIEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_66F25803C9BFBABB9A6CE4A7562B55E583C2FC70724987161257C860A4FBD952_1702860058717_neon.png" alt="Neon table" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This tutorial taught us how to leverage security and database management by integrating Auth0 with Neon Postgres as a custom database. Pairing Auth0 and Neon Postgres represents a pivotal leap toward fortifying modern applications with scalability, speed, and security. By adopting this strategic combination, developers can ensure a seamless and secure authentication process through Auth0 while leveraging the robust database management capabilities of Neon Postgres.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/configuring-postgresql-as-auth0-custom-database/#Testing-the-Database"&gt;Configuring PostgreSQL as Auth0 Custom Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/docs/get-started/auth0-overview/create-applications"&gt;Creating applications with Auth0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neon.tech/docs/introduction?ref=hm"&gt;Neon documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>authjs</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Basics of RAG with pgVector and Langchain</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Thu, 08 Feb 2024 08:47:49 +0000</pubDate>
      <link>https://dev.to/hackmamba/basics-of-rag-with-pgvector-and-langchain-3nob</link>
      <guid>https://dev.to/hackmamba/basics-of-rag-with-pgvector-and-langchain-3nob</guid>
      <description>&lt;p&gt;Retrieval augmented generation (RAG) is a technique that enhances the accuracy and reliability of generative AI models by augmenting their knowledge base with facts from external sources. RAG enables large language models (LLMs) to craft accurate, assertive, and brilliant responses on a subject matter. &lt;/p&gt;

&lt;p&gt;In this article, we’ll demonstrate how to use the RAG technique in a modern application. To do so, we’ll create a Flutter application using &lt;a href="https://langchaindart.com/#/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;Langchain&lt;/a&gt; for the LLM framework and &lt;a href="https://neon.tech/docs/extensions/pgvector?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;pgVector&lt;/a&gt;, an open-source Postgres extension for vector similarity search.&lt;/p&gt;

&lt;p&gt;Before beginning, you’ll need a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A good understanding of the &lt;a href="https://flutter.dev/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; framework and &lt;a href="https://dart.dev/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;dart programming&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://console.neon.tech/sign_in" rel="noopener noreferrer"&gt;Neon account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An OpenAI API key (meaning you’ll need an &lt;a href="https://auth0.openai.com/u/login/identifier?state=hKFo2SAyRXpraE12RzdfNzh2dmxadHNUakNiSTM0SmM2Y0hCRKFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIEJ3WlN3MnIzb0dKMUtsQXZsai1HTXk1RnJZXzZ0WVlvo2NpZNkgRFJpdnNubTJNdTQyVDNLT3BxZHR3QjNOWXZpSFl6d0Q" rel="noopener noreferrer"&gt;OpenAI account&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;And some cookies and coffee.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demystifying some concepts
&lt;/h2&gt;

&lt;p&gt;With the aid of databases, especially those that support vector capabilities like &lt;a href="https://neon.tech/?ref=hm" rel="noopener noreferrer"&gt;Neon&lt;/a&gt;, we can use the RAG technique to assist LLMs in delivering accurate answers to an end user. Neon is a fully managed serverless Postgres that provides separate storage and computing to offer autoscaling, branching, and bottomless storage. Neon is fully open source under the Apache 2.0 licenses, and we can find the &lt;a href="https://github.com/neondatabase/neon?ref=hm" rel="noopener noreferrer"&gt;neondatabase&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;Let’s first demystify some concepts, starting with &lt;a href="https://neon.tech/docs/extensions/pgvector?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;pgVector&lt;/a&gt;. pgVector is a Postgres extension that works with vector embeddings for storage, similarity search, and more. Enabling the pgVector extension in your Neon database simplifies storing vector embeddings as well as easy querying using the inner product (&lt;code&gt;&amp;lt;#&amp;gt;&lt;/code&gt;) or cosine distance (&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Langchain itself is not an LLM but a framework that aids application development with LLMs. Thus, it enables context-aware applications that need language models to reason. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That raises a burning question: How do these parts relate to one another?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RAG applications usually consist of two components: indexing and retrieval.&lt;/p&gt;

&lt;p&gt;The indexing process involves integrating (loading) the external data source, splitting it into smaller pieces, embedding the document as a vector, and storing it. &lt;/p&gt;

&lt;p&gt;Langchain handles splitting and embedding by providing the application access to OpenAI’s embedding API. Neon comes into play in the storage process.&lt;/p&gt;

&lt;p&gt;For the retrieval process, pgVector uses its vector similarity index capability to search the distance between the query vector and the stored vector in the Neon database. Then Langchain uses OpenAI as an LLM to generate the desired result from the query in natural language.&lt;/p&gt;

&lt;p&gt;The following sections will cover all the steps in building our application, from creating a Neon database to building the Flutter application. Let us set up a Neon account and create our database without further ado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Neon database
&lt;/h2&gt;

&lt;p&gt;After creating a Neon account, as specified earlier, let’s proceed to sign in to the &lt;a href="https://console.neon.tech/sign_in" rel="noopener noreferrer"&gt;account&lt;/a&gt; by selecting one of the methods provided for user authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700901557376_neon-sign-in.png" alt="Neon sign-in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successful sign-in, we’ll be redirected to a &lt;strong&gt;Create Project&lt;/strong&gt; screen on the home page, where we are asked to fill in our desired project name, postgres version, and database name. We can explore more options for changing the branch name to any other name, but let’s leave it as &lt;code&gt;main&lt;/code&gt; for now and click &lt;strong&gt;Create project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018153_create_project.png" alt="Create project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1700902018073_explore_options.png" alt="More options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterward, we are redirected to the home page, where we get a popup showing the connection details to the Neon project we created earlier. We need these details to access the Neon project from our application and copy it to a safe file. And with that, we have successfully created a Neon database for our Flutter application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701099281693_connection_details.png" alt="Connection details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neon provides three database management methods: the &lt;a href="https://neon.tech/docs/reference/cli-databases?ref=hm" rel="noopener noreferrer"&gt;Neon CLI&lt;/a&gt;(command line interface), the &lt;a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api?ref=hm" rel="noopener noreferrer"&gt;Neon API&lt;/a&gt;, and &lt;a href="https://neon.tech/docs/get-started-with-neon/query-with-neon-sql-editor?ref=hm" rel="noopener noreferrer"&gt;SQL&lt;/a&gt;. With SQL, Neon made an SQL editor available to run SQL commands directly on the console. Thus, we will use SQL to manage our Neon database, but we‘ll do so via a Postgres connection from our application to the Neon database.&lt;/p&gt;

&lt;p&gt;The Flutter application is a simple chatbot that responds to queries based on the data from the external data source—in this case, a PDF file. Therefore, in the coming sections, we will clone a Flutter template, connect the template to the Neon database, and add the functionalities to implement the RAG technique within the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Flutter application
&lt;/h2&gt;

&lt;p&gt;To begin, we will use a Flutter template application containing a display area, a text area where we will type our query, and a drawer with a button to upload our desired PDF.&lt;/p&gt;

&lt;p&gt;To clone the project, run the command below in a terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/muyiwexy/neon_rag_with_langchain.git&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After cloning the project, run the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This command obtains all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies.&lt;/p&gt;

&lt;p&gt;This project uses the Model View Controller (MVC) architecture to handle specific development aspects of the application. The architecture helps us maintain readability by separating the business (core) logic from the UI (presentation layer). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701102375667_template_result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701102375667_template_result.png" alt="Template result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701102375693_template_result_drawer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701102375693_template_result_drawer.png" alt="Template result drawer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make things easier to locate, here’s an ASCII representation of the &lt;code&gt;lib&lt;/code&gt; folder structure:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;widgets&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;display_area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;text_area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home_page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view_model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;dependency_injection&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Since we are using the &lt;a href="https://www.tutorialspoint.com/mvc_framework/mvc_framework_introduction.htm" rel="noopener noreferrer"&gt;MVC architecture&lt;/a&gt;, the UI code is placed in the &lt;code&gt;lib/home/view&lt;/code&gt; folder. To proceed, we need to add some external dependencies necessary for building the application to the &lt;code&gt;pubspec.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;file_picker&lt;/span&gt;
  &lt;span class="nx"&gt;flutter_dotenv&lt;/span&gt;
  &lt;span class="nx"&gt;langchain&lt;/span&gt;
  &lt;span class="nx"&gt;langchain_openai&lt;/span&gt;
  &lt;span class="nx"&gt;path_provider&lt;/span&gt;
  &lt;span class="nx"&gt;postgres&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;
  &lt;span class="nx"&gt;syncfusion_flutter_pdf&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After successfully doing this, we’ll create an abstraction for all the services needed throughout this project. Let’s call this abstract class &lt;code&gt;LangchainService&lt;/code&gt; — within it, we will implement the processes involved in implementing the RAG technique. So, next, locate the &lt;code&gt;lib/home/view_model&lt;/code&gt; folder and create a dart file &lt;code&gt;langchain_service.dart&lt;/code&gt; within it. To perform an abstraction, add the code below to the file:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LangchainService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Indexing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Load&lt;/strong&gt;&lt;br&gt;
The load process involves integrating the document into the system, which is usually offline. Thus, to achieve this, we will do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;file_picker&lt;/code&gt;  package to select the files from a local device&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;syncfusion_flutter_pdf&lt;/code&gt; package to read the document (PDF) and convert it to text&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;path_provider&lt;/code&gt; package to find commonly used file ecosystems such as the &lt;code&gt;temp&lt;/code&gt; or &lt;code&gt;AppData&lt;/code&gt; directories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared to the other services, the load process is offline; thus, we will perform this operation separately from the other processes. To load a file, create an &lt;code&gt;index_notifier.dart&lt;/code&gt; in the &lt;code&gt;lib/home/controller&lt;/code&gt;  directory. Next, we create a &lt;code&gt;ChangeNotifier&lt;/code&gt; class, &lt;code&gt;IndexNotifier&lt;/code&gt;, with a &lt;code&gt;final&lt;/code&gt; value of &lt;code&gt;LangchainService&lt;/code&gt;. Also, we will create two global private &lt;code&gt;String&lt;/code&gt; variables, &lt;code&gt;_filepath&lt;/code&gt; and &lt;code&gt;_fileName&lt;/code&gt;, and a getter for the &lt;code&gt;_fileName&lt;/code&gt; variable.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;LangchainService&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;_filepath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;_fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In essence, and by the &lt;code&gt;ChangeNotifier&lt;/code&gt;, this class will be one of two files that handle the state management load of the application. Next, we will implement a function that returns a type &lt;code&gt;Document&lt;/code&gt; from the &lt;code&gt;Langchain&lt;/code&gt; package. We will use the method to pick a PDF document from our local device and assign the file type and name to the &lt;code&gt;String&lt;/code&gt; variables created earlier.&lt;/p&gt;

&lt;p&gt;Also, we will have a &lt;code&gt;Future&lt;/code&gt; function that converts PDFs to text, which is loaded as &lt;code&gt;Documents&lt;/code&gt; using the &lt;code&gt;TextLoader&lt;/code&gt; class from &lt;code&gt;Langchain&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;


&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;_pickedFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;FilePickerResult&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;FilePicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pickFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;allowedExtensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;single&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;_fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;single&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;textfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="nx"&gt;_filepath&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isNotEmpty&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_readPDFandConvertToText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TextLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textfile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No file selected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;_readPDFandConvertToText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;File&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_filepath&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readAsBytes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;inputBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Uint8List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PdfTextExtractor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;extractText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;localPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;_localPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;File&lt;/span&gt; &lt;span class="nx"&gt;createFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$localPath/output.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;createFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeAsString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;_localPath&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getApplicationDocumentsDirectory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We can load a PDF as a Langchain &lt;code&gt;Document&lt;/code&gt; file with the code above. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split and embed&lt;/strong&gt;&lt;br&gt;
Now, we need to split and embed the &lt;code&gt;document&lt;/code&gt; and store it. To split and embed a Langchain document, we will return to the abstraction created in the &lt;code&gt;langchain_service.dart&lt;/code&gt;. There, we will update it with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LangchainService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitDocToChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;embedChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;We will create another file within the same directory called &lt;code&gt;langchain_service_impl.dart&lt;/code&gt; to implement this abstraction. Within this file, we’ll implement the &lt;code&gt;LangchainService&lt;/code&gt; abstraction created earlier. &lt;code&gt;splitDocToChunks&lt;/code&gt; takes in a parameter &lt;code&gt;Document&lt;/code&gt;, which is returned from the &lt;code&gt;_pickedFile&lt;/code&gt; method in the &lt;code&gt;IndexNotifier&lt;/code&gt; class earlier. It then gets the page content.&lt;/p&gt;

&lt;p&gt;Then, we use the &lt;code&gt;RecursiveCharacterTextSplitter&lt;/code&gt; object to create a document split text into several 1000-character chunks and return it as a &lt;code&gt;Document&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;Next, we will pass the &lt;code&gt;Document&lt;/code&gt; list to the &lt;code&gt;embedChunks&lt;/code&gt; method, which then creates vector embeddings of this List and returns it as a &lt;code&gt;List&amp;lt; List &amp;lt;double&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below is how the code should look:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LangchainServicesImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LangchainService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;OpenAIEmbeddings&lt;/span&gt; &lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nc"&gt;LangchainServicesImpl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitDocToChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textSplitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;textSplitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDocuments&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;/g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;embedChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;embedDocs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embedDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;embedDocs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Equally, we will update the &lt;code&gt;IndexNotifier&lt;/code&gt; class to control the state of our application while going through all these processes:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/a111e87cc1abeaa6a398474768565957#file-index_notifier-dart" rel="noopener noreferrer"&gt;index_notifier.dart&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Store&lt;/strong&gt;&lt;br&gt;
So far, we’ve successfully enabled loading, splitting, and embedding the PDF document. Now, we need to store the split and embedded data, which is where the Neon database we created earlier comes in. To do this, we will update the &lt;code&gt;LangchainService&lt;/code&gt; abstraction with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LangchainService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// the abstraction above&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkExtExist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;checkTableExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonVecorExt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;deleteNeonTableRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;storeDocumentData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;embeddedDoc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;checkExtExist&lt;/code&gt; method checks if the &lt;code&gt;vector&lt;/code&gt; extension exists and returns the result from the execution. Also, the &lt;code&gt;checkTableExist&lt;/code&gt; method checks if a table (the private String variable &lt;code&gt;_filename&lt;/code&gt; created earlier) exists within the Neon database and returns the result from the execution, which is a boolean. To do this, we will add the code below to implement the &lt;code&gt;LangchainService&lt;/code&gt; in the &lt;code&gt;langchain_service_impl.dart&lt;/code&gt; file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/963aeaf2545bb7c5f4fc2844287d6828#file-langchain_service_impl-dart" rel="noopener noreferrer"&gt;langchain_service_impl.dart&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Earlier, we mentioned that Neon allows us to write SQL commands directly on the console through their &lt;a href="https://console.neon.tech/app/projects/divine-sun-12551123/query" rel="noopener noreferrer"&gt;&lt;strong&gt;SQL Editor&lt;/strong&gt;&lt;/a&gt;. Equally, we can execute these SQL commands programmatically from Flutter using the &lt;code&gt;Postgres&lt;/code&gt; package. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The methods &lt;code&gt;createNeonVecorExt&lt;/code&gt;, &lt;code&gt;createNeonTable&lt;/code&gt;, and &lt;code&gt;deleteNeonTableRows&lt;/code&gt;, handle the creation of &lt;strong&gt;pgVector&lt;/strong&gt; extension, a Neon database table (the private String variable &lt;code&gt;_filename&lt;/code&gt; created earlier), and the deletion of any stored rows (this is in the case the user wants to update the document in the database table and there is a name clash) respectively. When creating the Neon table, we will simultaneously activate vector indexing using the &lt;code&gt;ivfflat&lt;/code&gt; algorithm from the &lt;strong&gt;pgVector&lt;/strong&gt; extension. This algorithm provides an efficient solution for approximate nearest neighbor search over high-dimensional data like embeddings.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/b44a481473fe68d908a33421c558fd87#file-langchain_service_impl-dart" rel="noopener noreferrer"&gt;langchain_service_impl.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;storeDocumentData&lt;/code&gt; we will pass the Langchain &lt;code&gt;Document&lt;/code&gt;, the chunks, the embedded chunks, and the table name to it and execute an &lt;code&gt;INSERT&lt;/code&gt; command in &lt;strong&gt;&lt;em&gt;transaction&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/631fbe15862215a55698a0e5be19f794#file-langchain_service_impl-dart" rel="noopener noreferrer"&gt;langchain_service_impl.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we will update the &lt;code&gt;IndexNotifier&lt;/code&gt;to implement the changes to our &lt;code&gt;LangchainServices&lt;/code&gt; accordingly. We will use the &lt;code&gt;checkExtExist&lt;/code&gt;  and &lt;code&gt;checkTableExist&lt;/code&gt; as conditional checkers to run the &lt;code&gt;createNeonVecorExt&lt;/code&gt;, &lt;code&gt;createNeonTable&lt;/code&gt;, and &lt;code&gt;deleteNeonTableRows&lt;/code&gt; as they satisfy each condition. Here is the updated code below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/aaf0043a04f9960d36d44abdf098f374#file-index_notifier-dart" rel="noopener noreferrer"&gt;index_notifier.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have successfully stored the PDF data within the database table as an &lt;strong&gt;id(text)&lt;/strong&gt;, &lt;strong&gt;Metadata (Map or &lt;code&gt;JSON&lt;/code&gt;)&lt;/strong&gt;, and &lt;strong&gt;embedding&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To utilize the &lt;code&gt;ChangeNotifier&lt;/code&gt; class within our application, we will mount the &lt;code&gt;ChangeNotifier&lt;/code&gt; class using &lt;code&gt;Provider&lt;/code&gt; for dependency injection. In this process, we will connect the Neon database and our Flutter application using the &lt;code&gt;Postgres&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;The way to do this is by wrapping the initial stateless widget in the &lt;code&gt;main.dart&lt;/code&gt; with a &lt;code&gt;MultiProvider&lt;/code&gt;. Doing this mounts our &lt;code&gt;Providers&lt;/code&gt; and &lt;code&gt;ChangeNotifierProviders&lt;/code&gt; to the widget tree, allowing us to monitor the state of our application easily. Thus, we will head to the &lt;code&gt;lib/core/dependency_injection/&lt;/code&gt; folder, create a file called &lt;code&gt;provider_locator.dart&lt;/code&gt;, and paste the code below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/54045436d58e6ab667c213fc2377bf53#file-provider_locator-dart" rel="noopener noreferrer"&gt;provider_locator.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ProviderLocator&lt;/code&gt; class does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines a method &lt;code&gt;getProvider&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Creates a &lt;code&gt;LangchainService&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Returns a &lt;code&gt;MultiProvider&lt;/code&gt; with a &lt;code&gt;LangchainService&lt;/code&gt; provider and a &lt;code&gt;ChangeNotifierProvider&lt;/code&gt; for &lt;code&gt;IndexNotifier&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Defines a method &lt;code&gt;_createLangchainService&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Creates a PostgreSQL connection.&lt;/li&gt;
&lt;li&gt;Creates an &lt;code&gt;OpenAIEmbeddings&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Creates an &lt;code&gt;OpenAI&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Returns a &lt;code&gt;LangchainServicesImpl&lt;/code&gt; instance with the created connection, embeddings, and OpenAI.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Defines a method &lt;code&gt;createPostgresConnection&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Tries to establish a PostgreSQL connection with specified settings from the Neon connection details earlier.&lt;/li&gt;
&lt;li&gt;If the connection fails, it retries up to a maximum number of times.&lt;/li&gt;
&lt;li&gt;If the connection is not established after maximum retries, it throws an exception.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Defines a method &lt;code&gt;_createEmbeddings&lt;/code&gt; that returns an &lt;code&gt;OpenAIEmbeddings&lt;/code&gt; instance.&lt;/li&gt;

&lt;li&gt;Defines a method &lt;code&gt;_createOpenAIConnection&lt;/code&gt; that returns an &lt;code&gt;OpenAI&lt;/code&gt; instance.&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: For security reasons, we will use a &lt;code&gt;.env&lt;/code&gt; file to secure our passkey. Kindly follow this &lt;a href="https://developer.school/tutorials/how-to-use-environment-variables-with-flutter-dotenv" rel="noopener noreferrer"&gt;article&lt;/a&gt; to learn more about how to use &lt;code&gt;flutter_dotenv&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let’s update the &lt;code&gt;main.dart&lt;/code&gt; file with the code below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/3ee7c27341c73ff33b42d4796fbd591a#file-home-dart" rel="noopener noreferrer"&gt;home.dart&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval
&lt;/h2&gt;

&lt;p&gt;Retrieval is a streamlined process commonly divided into two processes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve: This is done by comparing the vector embedding of a user query with the closest available result present in the database. We perform this comparison using the cosine similarity search to compare a vector with another. Thus, when we get the closest results, we can use it for the second process.&lt;/li&gt;
&lt;li&gt;Generate: After getting the closest result, we can use it as an assistant for the LLMs to generate responses based on that particular information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this programmatically, we will head to the &lt;code&gt;langchain_service.dart&lt;/code&gt; and in the abstraction, add this code below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LangchainService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;queryNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The method above returns a string response by following the retrieval process above. Here is the code for the implementation below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/muyiwexy/bbca1411fd10cdc94bc2dd1e28e6795b#file-langchain_service_impl-dart" rel="noopener noreferrer"&gt;langchain_service_impl.dart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code above does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implements a method &lt;code&gt;queryNeonTable&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Embeds the query using the &lt;code&gt;embeddings&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;Executes a SQL query on the &lt;code&gt;connection&lt;/code&gt; to get similar items from the specified table.&lt;/li&gt;
&lt;li&gt;Converts the result into a list of &lt;code&gt;Metadata&lt;/code&gt; objects.&lt;/li&gt;
&lt;li&gt;If Metadata is not empty, it concatenates the page content, creates a &lt;code&gt;StuffDocumentsQAChain&lt;/code&gt; object, and calls it with the concatenated content and the original query to get a response.&lt;/li&gt;
&lt;li&gt;If Metadata is empty, it returns a default message: “Couldn’t find anything on that topic”.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;We will then create a separate &lt;code&gt;ChangeNotifier&lt;/code&gt; class to handle the state of the query. This follows the same pattern as that of the &lt;code&gt;IndexNotifier&lt;/code&gt; class with some slight changes. Here is the code below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../view_models/langchain_services.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;LangchainService&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;_messagesState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;messageState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_messagesState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;_queryState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ValueNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;queryState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;userqueryResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;_messagesState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryNeonTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updatedMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;updatedMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;_messagesState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;updatedMessages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle errors if necessary&lt;/span&gt;
      &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;milliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;_queryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;QueryState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The code above does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defines a &lt;code&gt;Message&lt;/code&gt; class with &lt;code&gt;query&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; fields.&lt;/li&gt;
&lt;li&gt;Defines an &lt;code&gt;enum&lt;/code&gt; called &lt;code&gt;QueryState&lt;/code&gt; with states: &lt;code&gt;initial&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;loaded&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creates a &lt;code&gt;QueryNotifier&lt;/code&gt; class that extends &lt;code&gt;ChangeNotifier&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;Initializes a &lt;code&gt;LangchainService&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;Maintains a list of &lt;code&gt;Message&lt;/code&gt; objects.&lt;/li&gt;
&lt;li&gt;Defines &lt;code&gt;ValueNotifier&lt;/code&gt; objects for &lt;code&gt;messagesState&lt;/code&gt; and &lt;code&gt;queryState&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Defines a method &lt;code&gt;userqueryResponse&lt;/code&gt; that:

&lt;ul&gt;
&lt;li&gt;Adds a new &lt;code&gt;Message&lt;/code&gt; to &lt;code&gt;_messages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Sets the &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;loading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;queryNeonTable&lt;/code&gt; method of &lt;code&gt;langchainService&lt;/code&gt; to get a response.&lt;/li&gt;
&lt;li&gt;Updates the last message’s response and sets &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;loaded&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Handles errors by setting &lt;code&gt;queryState&lt;/code&gt; to &lt;code&gt;error&lt;/code&gt;, then back to &lt;code&gt;initial&lt;/code&gt; after a delay.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After, we will update the &lt;code&gt;getProvider&lt;/code&gt; method in the &lt;code&gt;provider_locator.dart&lt;/code&gt; file by adding another &lt;code&gt;ChangeNotifierProvider&lt;/code&gt; class to the &lt;code&gt;MultiProvider&lt;/code&gt;. Here is how the code is below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProviderLocator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// provider tree&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MultiProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_createLangchainService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MultiProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LangchainService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;// IndexNotifier&lt;/span&gt;
        &lt;span class="nx"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IndexNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;IndexNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="c1"&gt;// QueryNotifier&lt;/span&gt;
        &lt;span class="nx"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;QueryNotifier&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;QueryNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;langchainService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;That is it — we should have the result for the application as below:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://app.opentape.io/share/4c33bc95-9f07-4323-acc6-fb6b1219cf8a" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapp.opentape.io%2Fthumbnail%2F4c33bc95-9f07-4323-acc6-fb6b1219cf8a" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://app.opentape.io/share/4c33bc95-9f07-4323-acc6-fb6b1219cf8a" rel="noopener noreferrer" class="c-link"&gt;
          neon and langchain | Opentape
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Muyiwa Femi-Ige - Feb 7th, 3:10pm
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapp.opentape.io%2Ffavicon.ico"&gt;
        app.opentape.io
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701224594364_embeddings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_0F1F35A31B87D9FE2BC161DA638BA2CAFBC4BDCDC924430F421BE8C7E4BEB0A0_1701224594364_embeddings.png" alt="neon database result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here is a link to the &lt;a href="https://github.com/muyiwexy/neon_rag_with_langchain/blob/functionalities/lib/home/controller/query_notifier.dart" rel="noopener noreferrer"&gt;repository&lt;/a&gt; containing all the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Retrieval augmented generation (RAG) enhances LLMs by integrating techniques to ensure a factual and contextual response. The collaboration of a vector database like Neon with the RAG technique and Langchain elevate the capabilities of learnable machines to unprecedented levels. This leads to more brilliant virtual assistants, data analysis tools, and more.&lt;/p&gt;

&lt;p&gt;In conclusion, the integration of RAG with pgVector and Langchain is a testament to the incredible prowess of AI and its hopeful future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Here are some resources that will guide you more in this journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://python.langchain.com/docs/use_cases/question_answering/?utm_source=hackmamba&amp;amp;utm_medium=blog&amp;amp;utm_id=HMBcommunity" rel="noopener noreferrer"&gt;Retrieval-augmented generation&lt;/a&gt; &lt;a href="https://python.langchain.com/docs/use_cases/question_answering/" rel="noopener noreferrer"&gt;(RAG)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.openai.com/t/vector-similarity-search-in-postgres-with-pgvector-text-embedding-ada-002-and-bit-io/150558" rel="noopener noreferrer"&gt;Vector Similarity Search in Postgres with pgvector, text-embedding-ada-002, and bit.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=y2va_4m9FLQ" rel="noopener noreferrer"&gt;How to build a PDF.ai clone with Flutter, Pinecone Vector Database, Langchain, and ChatGPT without any backend or Python.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>sql</category>
      <category>flutter</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to add push notifications to your Appwrite Cloud apps</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Thu, 07 Dec 2023 14:38:00 +0000</pubDate>
      <link>https://dev.to/hackmamba/how-to-add-push-notifications-to-your-appwrite-cloud-apps-5ffn</link>
      <guid>https://dev.to/hackmamba/how-to-add-push-notifications-to-your-appwrite-cloud-apps-5ffn</guid>
      <description>&lt;p&gt;In today's information-driven landscape, staying current is paramount. Enter the realm of push notifications — an avenue by which data arrives at our digital doorstep, like a knowledgeable neighbor extending a warm invitation. These little alerts have become one of the most essential features in modern-day applications as they update the user about the services that a given application handles. &lt;/p&gt;

&lt;p&gt;Let’s explore push notifications a bit further: messages or alerts sent from a server or backend system to a user's mobile device, computer, or other device. These notifications are "pushed" to the device rather than being requested or "pulled" by the user. &lt;/p&gt;

&lt;p&gt;In the case of our analogy above, the friendly neighbor is Appwrite. Appwrite is an open-source backend-as-a-service (BaaS) that simplifies repetitive development tasks through simple REST API. Appwrite has added this important feature to its services. In this article, we’ll take a closer look at how we can add push notifications to our Flutter applications using Appwrite's cloud functions.&lt;/p&gt;

&lt;p&gt;Before we can proceed, you’ll need to have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://cloud.appwrite.io/register?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite cloud&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://console.firebase.google.com/u/1/?pli=1" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; account (subsequently, a &lt;a href="https://accounts.google.com/v3/signin/identifier?continue=https://mail.google.com/mail/&amp;amp;service=mail&amp;amp;theme=glif&amp;amp;flowName=GlifWebSignIn&amp;amp;flowEntry=ServiceLogin" rel="noopener noreferrer"&gt;Gmail&lt;/a&gt; account)&lt;/li&gt;
&lt;li&gt;A good foundation in Flutter&lt;/li&gt;
&lt;li&gt;And some coffee for the cookies, of course. 😉&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.appwrite.io/register?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Cloud&lt;/a&gt; implements push notifications in its application by combining the &lt;strong&gt;Firebase Cloud Messaging (FCM)&lt;/strong&gt; feature provided by &lt;strong&gt;Firebase&lt;/strong&gt; and its own &lt;strong&gt;Appwrite Cloud Function API&lt;/strong&gt;. Appwrite further simplifies this process programmatically by providing a serverless &lt;strong&gt;Node.js&lt;/strong&gt; code template that allows us to connect our Flutter application to communicate with &lt;strong&gt;Firebase Cloud Messaging&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We’re going to get pretty granular in this tutorial, so here’s a helpful outline: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Creating projects:

&lt;ul&gt;
&lt;li&gt;Create a Firebase project&lt;/li&gt;
&lt;li&gt;Create an Appwrite project&lt;/li&gt;
&lt;li&gt;Create our Flutter project&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Setting up Firebase Cloud messaging:

&lt;ul&gt;
&lt;li&gt;Generating a private key&lt;/li&gt;
&lt;li&gt;Creating a Realtime database&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Setting up Appwrite:

&lt;ul&gt;
&lt;li&gt;Creating an Appwrite database&lt;/li&gt;
&lt;li&gt;Creating an Appwrite Cloud function FCM template&lt;/li&gt;
&lt;li&gt;Customizing the FCM template&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Building the Flutter project:

&lt;ul&gt;
&lt;li&gt;Cloning the application for the notification device&lt;/li&gt;
&lt;li&gt;Cloning the application for the admin device&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating projects
&lt;/h2&gt;

&lt;p&gt;Thus, without further ado, let’s create the Firebase project!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698480134782_excited-shaquille-o-neal-3isxv4tbjeeb3fej.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698480134782_excited-shaquille-o-neal-3isxv4tbjeeb3fej.gif" alt="Excited"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Firebase project
&lt;/h2&gt;

&lt;p&gt;To create a &lt;a href="https://console.firebase.google.com/u/1/?pli=1" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; project, click the earlier link and click &lt;strong&gt;Create a project&lt;/strong&gt; on the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698481037670_create%2Bproject.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698481037670_create%2Bproject.png" alt="Create project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, Firebase prompts us to fill in a &lt;strong&gt;project name&lt;/strong&gt;, &lt;strong&gt;turn on or off analytics&lt;/strong&gt; (uncheck analytics as it is optional for this project), and finally, &lt;strong&gt;continue&lt;/strong&gt;. That’s it! You have now successfully created a Firebase project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333216_project_name.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333216_project_name.PNG" alt="Add project name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333370_disabling_analytics.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333370_disabling_analytics.PNG" alt="Analytics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333289_continue.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698482333289_continue.PNG" alt="Continue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Appwrite project
&lt;/h2&gt;

&lt;p&gt;After creating an Appwrite cloud account,  log into the console, click &lt;strong&gt;Create Project&lt;/strong&gt;, and fill in a project name and ID here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: ID can also be autogenerated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698586002630_create%2Bproject.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698586002630_create%2Bproject.PNG" alt="Create an Appwrite project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Flutter project
&lt;/h2&gt;

&lt;p&gt;To create a Flutter project, open your terminal and type the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: Change the  to a name of your choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The command above triggers the Flutter SDK to create a new boilerplate project; thus, we have successfully created a Firebase, Appwrite, and Flutter project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Firebase Cloud Messaging
&lt;/h2&gt;

&lt;p&gt;To use the Firebase cloud messaging feature within our Appwrite cloud applications, we will need to get the &lt;strong&gt;private key&lt;/strong&gt; and &lt;strong&gt;database URL&lt;/strong&gt; from the Firebase console. &lt;/p&gt;
&lt;h2&gt;
  
  
  Generating a private key
&lt;/h2&gt;

&lt;p&gt;Starting with the private key, we will navigate to the console's &lt;strong&gt;Project settings&lt;/strong&gt; area by clicking the gear icon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588391391_settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588391391_settings.png" alt="Project settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will copy the &lt;strong&gt;project ID&lt;/strong&gt; to a safe place, as we will require it when creating the &lt;strong&gt;FCM template&lt;/strong&gt; in Appwrite. We must provide the project ID as a variable, which we will then pass to the &lt;strong&gt;FCM template&lt;/strong&gt; as a parameter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588600368_projectId.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698588600368_projectId.png" alt="Project ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll move to the &lt;strong&gt;Service accounts&lt;/strong&gt; section of the &lt;strong&gt;Project Settings&lt;/strong&gt; area and click &lt;strong&gt;Generate new private key&lt;/strong&gt;, then &lt;strong&gt;Generate key&lt;/strong&gt;. Doing this will download a JSON file containing important information to our PC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270518_generate%2Bprivate%2Bkey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270518_generate%2Bprivate%2Bkey.png" alt="Generate private key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270473_generate%2Bkey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698589270473_generate%2Bkey.png" alt="Generate key"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Realtime database
&lt;/h2&gt;

&lt;p&gt;There are two options for databases to select from within Firebase; for this project, either is effective. For this project, we will choose the &lt;strong&gt;Realtime database&lt;/strong&gt; as our choice. Thus, enlarge the build section within the Firebase console, select &lt;strong&gt;Realtime database,&lt;/strong&gt; and click &lt;strong&gt;Create database.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590435208_realtime%2Bdatabase%2Bbuild.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590435208_realtime%2Bdatabase%2Bbuild.png" alt="Realtime database build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590740606_create%2Bdatabase.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698590740606_create%2Bdatabase.png" alt="Create database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will prompt a pop-up asking us to set up the database. Select the &lt;strong&gt;United States (us-central1)&lt;/strong&gt; as your preferred database location. Select &lt;strong&gt;Start in&lt;/strong&gt; &lt;strong&gt;Test mode&lt;/strong&gt; for the security rules, as we are not using the database for any production purpose. Then click &lt;strong&gt;Enable&lt;/strong&gt; to create the &lt;strong&gt;Realtime database.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130960_setup%2Bdatabase.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130960_setup%2Bdatabase.PNG" alt="Set up a database location"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130799_security%2Brules.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591130799_security%2Brules.PNG" alt="Set up database security rules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the database URL is essential for what we want to build — so let’s copy the URL to a safe place and move to the next item on the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591856293_copy%2Bdatabase%2Burl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698591856293_copy%2Bdatabase%2Burl.png" alt="Realtime database URL"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up Appwrite
&lt;/h2&gt;

&lt;p&gt;Now that we have successfully gotten the &lt;strong&gt;private key&lt;/strong&gt; and &lt;strong&gt;database URL&lt;/strong&gt;, the next step is to create an Appwrite database and cloud function and customize the FCM cloud function template.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating an Appwrite database
&lt;/h2&gt;

&lt;p&gt;After creating an Appwrite project, navigate to the database section within the Appwrite console and click &lt;strong&gt;Create database.&lt;/strong&gt; Next, we will create a collection with a single &lt;code&gt;String&lt;/code&gt; attribute called &lt;strong&gt;Token.&lt;/strong&gt; This attribute will be the placeholder for the device token generated from the device we intend to receive the push notification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699890746001_create%2Bdatabase.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699890746001_create%2Bdatabase.png" alt="create databases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045846_create%2Bcollection.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045846_create%2Bcollection.png" alt="Create collections"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045887_attributes.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891045887_attributes.png" alt="Create attributes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After, move to the collection's settings and add permissions by setting the role to &lt;strong&gt;any&lt;/strong&gt; and selecting all the &lt;strong&gt;CRUD&lt;/strong&gt; (create, read, update, and delete) permissions. Setting permissions allows anyone with the database ID and collection ID (in this case, the admin) to access the notification device token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259594_permissions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259594_permissions.png" alt="Roles"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259641_permissions%2Band%2Broles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891259641_permissions%2Band%2Broles.png" alt="Permissions"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating an Appwrite Cloud function FCM template
&lt;/h2&gt;

&lt;p&gt;Appwrite's application of simple yet effective designs makes navigation relatively smooth — this is evident in the creation of &lt;strong&gt;Functions,&lt;/strong&gt; as all that is required is to select &lt;strong&gt;Functions&lt;/strong&gt; in the console from the navigation bar. To create the FCM template, select the &lt;strong&gt;Create function&lt;/strong&gt; button within the function area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891477676_function.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891477676_function.png" alt="Functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, a pop-up appears, showing all kinds of functions available to the Appwrite cloud. We will proceed to select &lt;strong&gt;All templates&lt;/strong&gt; in the bottom right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891621852_all%2Btemplates.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699891621852_all%2Btemplates.png" alt="All templates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;All templates&lt;/strong&gt; section, we can filter our template search by &lt;strong&gt;use case&lt;/strong&gt; or &lt;strong&gt;runtime&lt;/strong&gt; or search it by a named keyword. Using the &lt;strong&gt;use case&lt;/strong&gt; filter, we will select the messaging option, select &lt;strong&gt;push notification with FCM&lt;/strong&gt; among the options given, and click &lt;strong&gt;Create function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897042299_function%2Bfcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897042299_function%2Bfcm.png" alt="fcm_functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Appwrite further prompts us to sort out the configuration of the function by setting a &lt;strong&gt;name&lt;/strong&gt; (any name of our choosing) and &lt;strong&gt;runtime&lt;/strong&gt; (Node.js 18.0). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892062777_configuration.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892062777_configuration.png" alt="Configurations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Variables&lt;/strong&gt; section is where the primary business lies, where we must add some information in the &lt;strong&gt;private key JSON file&lt;/strong&gt; and the &lt;strong&gt;database URL&lt;/strong&gt; copied from the Firebase project earlier. So, from the &lt;strong&gt;private key JSON file&lt;/strong&gt;, we will copy out the &lt;strong&gt;project ID&lt;/strong&gt; (alternatively, we can get the &lt;strong&gt;project ID&lt;/strong&gt; from the Firebase project settings), &lt;strong&gt;private key,&lt;/strong&gt; and &lt;strong&gt;client_email.&lt;/strong&gt; Also, we will add the URL from the Realtime database — then, we are good to go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892227366_variables.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892227366_variables.PNG" alt="Variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698623398582_private%2Bkey%2Bjson%2Bfile.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698623398582_private%2Bkey%2Bjson%2Bfile.png" alt="Private key JSON"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Connect&lt;/strong&gt; section, we can add the template to an available repository or create a new one. For the tutorial's sake, we will select &lt;strong&gt;Create a new repository&lt;/strong&gt;, then click next to set up the &lt;strong&gt;Git organization&lt;/strong&gt; and the &lt;strong&gt;repository name&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403895_connect.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403895_connect.PNG" alt="Connect"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403844_repository.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892403844_repository.png" alt="Repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we can specify our preferred Git branch intended for the template (it is &lt;strong&gt;main&lt;/strong&gt; by default). After completing all the steps, we can create a push notification FCM template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892790201_branch.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699892790201_branch.PNG" alt="Branch"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Customzing the FCM template code
&lt;/h2&gt;

&lt;p&gt;To customize the FCM template code, head to the repository containing the template code on GitHub, and from the &lt;strong&gt;code&lt;/strong&gt; section, navigate to the &lt;strong&gt;src&lt;/strong&gt; folder. The &lt;strong&gt;src&lt;/strong&gt; folder contains two files: &lt;code&gt;main.js&lt;/code&gt; and &lt;code&gt;utils.js&lt;/code&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;main.js&lt;/code&gt; file with the code below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;throwIfMissing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendPushNotification&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./utils.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;throwIfMissing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FCM_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FCM_PRIVATE_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FCM_CLIENT_EMAIL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FCM_DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;throwIfMissing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deviceToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;throwIfMissing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Sending message to device: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FCM_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendPushNotification&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Successfully sent message: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Failed to send the message &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also, we will update the &lt;code&gt;utils.js&lt;/code&gt; file with the code below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Throws an error if any of the keys are missing from the object
 * @param {*} obj
 * @param {string[]} keys
 * @throws {Error}
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;throwIfMissing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Missing required fields: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @param {admin.messaging.Message} payload
 * @returns {Promise&amp;lt;string&amp;gt;}
 */&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendPushNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FCM_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;clientEmail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FCM_CLIENT_EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FCM_PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;n/gm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="na"&gt;databaseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FCM_DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After doing that, let’s commit our changes. Due to Appwrite’s connection to our GitHub, the commit automatically triggers the cloud Function to redeploy as it monitors changes in the attached repository.&lt;/p&gt;

&lt;p&gt;Now, we’re ready to clone the Flutter applications — both the admin (trigger application) and push notification application (receiver application).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698625757155_2DV.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698625757155_2DV.gif" alt="Joy"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the Flutter project
&lt;/h2&gt;

&lt;p&gt;Earlier in the article, we indicated that we would build two Flutter applications during the project. One is the device receiving the push notification; the other will be an admin device that triggers the Appwrite cloud FCM template. Doing this gives us a better use case for push notifications programmatically. Let’s get into it. &lt;/p&gt;
&lt;h2&gt;
  
  
  Cloning the application for the notification device
&lt;/h2&gt;

&lt;p&gt;In this section, we will clone the application for the notification device from this &lt;a href="https://github.com/muyiwexy/push_notification_app" rel="noopener noreferrer"&gt;repository&lt;/a&gt;. The application’s UI contains a button that uploads the phone token obtained from an FCM request.&lt;/p&gt;

&lt;p&gt;After cloning the application to local storage, open it in your preferred code editor and run the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command obtains all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies. Next, run the command &lt;code&gt;flutter run&lt;/code&gt;, and the application should look like the video below:&lt;/p&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/f5638d03f3294a8f8441868703ce4e77"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;To send a push notification, a token from the recipient device must be available to the Firebase cloud messaging service. The question now is,  how can we achieve that? &lt;/p&gt;

&lt;p&gt;The first step involves adding our Flutter project to the Firebase project created earlier. So, starting with that, we can achieve that manually through the Firebase console or using the &lt;strong&gt;Firebase CLI&lt;/strong&gt; (command line interface).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Firebase CLI&lt;/strong&gt; is a simple tool that allows easy interactions with Firebase using the command line. The &lt;strong&gt;Firebase CLI&lt;/strong&gt; provides commands that let us send specific requests to Firebase and get adequate responses. Some of these requests include the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Authentication and Authorization&lt;/li&gt;
&lt;li&gt;Real-time Database&lt;/li&gt;
&lt;li&gt;Hosting&lt;/li&gt;
&lt;li&gt;Cloud Functions&lt;/li&gt;
&lt;li&gt;Cloud Storage&lt;/li&gt;
&lt;li&gt;Firestore&lt;/li&gt;
&lt;li&gt;Test Lab&lt;/li&gt;
&lt;li&gt;Analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, to use the Firebase CLI for project setup within a Flutter project, let’s head back to the Firebase console. Within the base console are two options for connecting an Android application to Firebase. So, we will select the second option that says &lt;strong&gt;Flutter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698126048_create%2Bflutter%2Bproject.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698126048_create%2Bflutter%2Bproject.png" alt="flutter project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we click the option, the first step asks that we install the &lt;a href="https://firebase.google.com/docs/cli?hl=en&amp;amp;authuser=0&amp;amp;_gl=1*tcd4ob*_ga*MTc5MzYyNzA1NC4xNjk4MDYyNDUz*_ga_CW55HF8NVT*MTY5ODY5NzgzMC4yNC4xLjE2OTg2OTgxMzUuNjAuMC4w#windows-standalone-binary" rel="noopener noreferrer"&gt;Firebase CLI.&lt;/a&gt; According to the link, there are several methods we can follow to install the &lt;a href="https://firebase.google.com/docs/cli?hl=en&amp;amp;authuser=0&amp;amp;_gl=1*tcd4ob*_ga*MTc5MzYyNzA1NC4xNjk4MDYyNDUz*_ga_CW55HF8NVT*MTY5ODY5NzgzMC4yNC4xLjE2OTg2OTgxMzUuNjAuMC4w#windows-standalone-binary" rel="noopener noreferrer"&gt;Firebase CLI&lt;/a&gt;, depending on our device’s operating system. We will use the node package manager (npm) to install the CLI for uniformity. Here is a guide on &lt;a href="https://www.pluralsight.com/guides/getting-started-with-nodejs" rel="noopener noreferrer"&gt;how to install Node.js&lt;/a&gt; on your device.&lt;/p&gt;

&lt;p&gt;After installing Node.js, run the command below within your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tools&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698762380_installing%2Bfirebase%2Bcli.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698698762380_installing%2Bfirebase%2Bcli.PNG" alt="firebase cli"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Doing this automatically installs the &lt;strong&gt;Firebase CLI&lt;/strong&gt; to our preferred device, and with that, we can proceed to the next step of logging into our Firebase console via the CLI. To do that, we will use the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;firebase&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After logging into the &lt;strong&gt;Firebase CLI&lt;/strong&gt;, we must install the &lt;a href="https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase." rel="noopener noreferrer"&gt;FlutterFire plugin&lt;/a&gt; to create a new Firebase project in Dart. FlutterFire is a set of plugins that connects our Flutter project to Firebase. To activate the &lt;a href="https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase." rel="noopener noreferrer"&gt;FlutterFire plugin&lt;/a&gt; on our PC, use the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dart&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="nx"&gt;activate&lt;/span&gt; &lt;span class="nx"&gt;flutterfire_cli&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To use the &lt;a href="https://firebase.flutter.dev/docs/overview/#:~:text=FlutterFire%20is%20a%20set%20of,your%20Flutter%20application%20to%20Firebase." rel="noopener noreferrer"&gt;FlutterFire plugin&lt;/a&gt; to configure our Firebase project within the Flutter app, we must open a terminal within the Flutter project folder and then run this command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutterfire&lt;/span&gt; &lt;span class="nx"&gt;configure&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Firebase&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: Remember to change the &lt;code&gt;&amp;lt;Firebase Project ID&amp;gt;&lt;/code&gt; in the command above to the ID of the Firebase project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121567_flutter%2Bfire1.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121567_flutter%2Bfire1.PNG" alt="flutter_fire"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121500_flutter%2Bfire2.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698700121500_flutter%2Bfire2.PNG" alt="flutter_fire_2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting what platform(s) the configuration should support, the CLI will add some essential files to the Flutter project, and we are good to proceed.&lt;/p&gt;

&lt;p&gt;Next, we will connect our Flutter application to Appwrite. We do this to upload the generated token from our notification device to a general database — this allows a central admin to access the token and send push notifications accordingly to several devices.&lt;/p&gt;

&lt;p&gt;Here is how to connect an IOS or Android device in Flutter to Appwrite:&lt;/p&gt;
&lt;h2&gt;
  
  
  iOS
&lt;/h2&gt;

&lt;p&gt;First, obtain the &lt;code&gt;bundle ID&lt;/code&gt; by navigating to the &lt;code&gt;project.pbxproj&lt;/code&gt; file (&lt;code&gt;ios &amp;gt; Runner.xcodeproj &amp;gt; project.pbxproj&lt;/code&gt;) and searching for the &lt;code&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, navigate to the &lt;code&gt;Runner.xcworkspace&lt;/code&gt; folder in the application’s iOS folder in the project directory on &lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt;. To select the runner target, choose the &lt;strong&gt;Runner&lt;/strong&gt; project in the Xcode project navigator and find the &lt;code&gt;Runner target&lt;/code&gt;. Next, select &lt;code&gt;General and IOS 11.0&lt;/code&gt; as the target in the deployment info section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" alt="iOS"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Android
&lt;/h2&gt;

&lt;p&gt;For Android, copy the XML script below and paste it below the activity tag in the &lt;code&gt;Androidmanifest.xml&lt;/code&gt; file (to find this file, head to &lt;code&gt;android &amp;gt; app &amp;gt; src &amp;gt; main&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will also need to set up a platform within the Appwrite console. Follow the steps below to do so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Within the Appwrite console, select &lt;code&gt;Create Platform&lt;/code&gt; and choose &lt;code&gt;Flutter&lt;/code&gt; for the platform type.&lt;/li&gt;
&lt;li&gt;Specify the operating system: in this case, Android.&lt;/li&gt;
&lt;li&gt;Finally, provide the application and package names (found in the app-level &lt;code&gt;build.gradle&lt;/code&gt; file).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340142_account%2Binformation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340142_account%2Binformation.png" alt="Create platform 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340061_platform.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897340061_platform.png" alt="Create platform 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloning the application for the admin device
&lt;/h2&gt;

&lt;p&gt;In this section, we will clone the application for the admin device. The application’s UI contains a button that triggers the cloud function.  Let’s clone the &lt;a href="https://github.com/muyiwexy/application_admin" rel="noopener noreferrer"&gt;repository&lt;/a&gt; specified in the prerequisites. &lt;/p&gt;

&lt;p&gt;After cloning the application to local storage, we will open it in our preferred code editor and run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command obtains all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies. Next, run the command &lt;code&gt;flutter run&lt;/code&gt;, and our application should look like the images below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704216806_admin%2Bapp%2Blogin%2Bpage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704216806_admin%2Bapp%2Blogin%2Bpage.png" alt="admin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704277536_send%2Bpush%2Bnotification.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1698704277536_send%2Bpush%2Bnotification.PNG" alt="send_push_notification"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, when we click the &lt;code&gt;Send Push Notification&lt;/code&gt; button, it triggers this function in the &lt;code&gt;app_controller.dart&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;requestBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deviceToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification Body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;functionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Appconstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;functionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;jsonEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This function encodes a &lt;code&gt;Map&amp;lt;String, dynamic&amp;gt;&lt;/code&gt; into a &lt;code&gt;JSON&lt;/code&gt; and programmatically sends a &lt;code&gt;POST&lt;/code&gt; request to the Appwrite Function. Without an admin page, we can trigger these notifications within the Appwrite console.&lt;/p&gt;

&lt;p&gt;To do this, navigate to the Function section of the console, and within the FCM cloud function template, select &lt;code&gt;Execute now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736717_function%2Bfcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736717_function%2Bfcm.png" alt="function_fcm"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736659_execute%2Bfunction.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_3392CCDCA2CAACDA45CF9CBB11545BCDFE494F8FF34B843CE53D48CA079F66D2_1699897736659_execute%2Bfunction.png" alt="execute_fcm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will leave the &lt;strong&gt;Path&lt;/strong&gt; as it is in the pop-up, but we‘ll change the method to &lt;strong&gt;POST&lt;/strong&gt;. In the &lt;strong&gt;Advanced settings&lt;/strong&gt; section within the pop-up, add a Header with its name being &lt;strong&gt;Content-Type&lt;/strong&gt; and value being &lt;code&gt;application/json&lt;/code&gt;. Finally, in the body section, we will add a &lt;code&gt;JSON&lt;/code&gt; that looks like the format below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deviceToken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;notification device token&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;how are you&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we will execute the function, and the result should look like the GIF below:&lt;/p&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/3cfab1bb1a8d440787a2b910b1235d46"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Push notifications are hugely important in modern applications. By incorporating push notifications into our Appwrite Cloud applications, we can keep our users informed and engaged. Leveraging this powerful communication channel ensures that our audience receives timely updates, personalized messages, and essential information — enhancing their overall experience. &lt;/p&gt;

&lt;p&gt;With our backend configuration and error handling in place, we can reliably deliver push notifications while minimizing potential issues. Integrating push notifications into our applications is a valuable strategy for boosting user engagement and ensuring effective communication with our user base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;Here are some additional resources that you might find useful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/references/cloud/client-web/databases?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/references/cloud/client-web/functions?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/references/cloud/client-web/account?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/android-news/serverless-notifications-with-cloud-functions-for-firebase-685d7c327cd4?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Serverless notifications with Cloud Functions for Firebase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firebase</category>
      <category>cloud</category>
      <category>flutter</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>Implementing OAuth2 Clients with Flutter made simple</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Thu, 07 Sep 2023 11:47:38 +0000</pubDate>
      <link>https://dev.to/hackmamba/implementing-oauth2-clients-with-flutter-made-simple-n4l</link>
      <guid>https://dev.to/hackmamba/implementing-oauth2-clients-with-flutter-made-simple-n4l</guid>
      <description>&lt;p&gt;Having to input our information every time we register for a new service is tiring. With open authorization or OAuth2, we no longer have to undergo that pain. Open authorization is a design that lets websites and applications access certain hosted resources from a provider by request from the user. These resources can range from the user’s registered email address to personal information to cloud data.&lt;/p&gt;

&lt;p&gt;This article will show how to implement OAuth2 in a Flutter application with Google as the provider and Appwrite as the OAuth2 Client.&lt;br&gt;
&lt;a href="https://github.com/muyiwexy/google_auth_flutter.git" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is the link to the repository containing the code for this project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The following are required to follow along with this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic understanding of Dart and Flutter&lt;/li&gt;
&lt;li&gt;Flutter &lt;a href="https://flutter.dev/docs/get-started/install" rel="noopener noreferrer"&gt;SDK&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt; with a developer account&lt;/li&gt;
&lt;li&gt;Appwrite account; &lt;a href="https://cloud.appwrite.io/register?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;s&lt;/a&gt;&lt;a href="https://cloud.appwrite.io/register?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;ign-up&lt;/a&gt; is completely free&lt;/li&gt;
&lt;li&gt;A Gmail account; &lt;a href="https://accounts.google.com/signup/v2/createaccount?flowName=GlifWebSignIn&amp;amp;flowEntry=SignUp" rel="noopener noreferrer"&gt;s&lt;/a&gt;&lt;a href="https://accounts.google.com/signup/v2/createaccount?flowName=GlifWebSignIn&amp;amp;flowEntry=SignUp" rel="noopener noreferrer"&gt;ign-up&lt;/a&gt; is completely free&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Creating an Appwrite project
&lt;/h2&gt;

&lt;p&gt;After registering on the Appwrite cloud platform, we will be redirected to an onboarding page where we will have to create a new project. We will fill in our preferred project name and ID (optional as ID can be autogenerated), then select &lt;strong&gt;Create Project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4ynzmtpinwvsjevu06p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4ynzmtpinwvsjevu06p.png" alt="create-project" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating a new project, we must register our application to a specific platform within our project. Therefore, in the &lt;strong&gt;Add platform&lt;/strong&gt; area of the &lt;strong&gt;Home&lt;/strong&gt; section, we will select the &lt;code&gt;Flutter App&lt;/code&gt; button and select our preferred operating system (in this case, &lt;code&gt;Android&lt;/code&gt;). Then, we will fill in the &lt;strong&gt;application&lt;/strong&gt; and &lt;strong&gt;package&lt;/strong&gt; &lt;strong&gt;names&lt;/strong&gt; (the package name is in the app-level &lt;code&gt;build.gradle&lt;/code&gt; file).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxg8372q8ove60n144fk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxg8372q8ove60n144fk.png" alt="platform" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrb7c60bmdzjw408ok4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffrb7c60bmdzjw408ok4v.png" alt="Flutter platform" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;We will start by cloning the project repository to our PC. This repository contains the template and code we will use for the project. To clone the repository, run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/muyiwexy/google_auth_flutter.git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the cloning process, we will run the command &lt;code&gt;flutter pub get&lt;/code&gt; to load all the packages used in the project to our PC.&lt;/p&gt;

&lt;p&gt;Finally, we will run the project using the command &lt;code&gt;flutter run&lt;/code&gt; and we should have the result below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzalsbue9s3ox68r9w4l7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzalsbue9s3ox68r9w4l7.png" alt="template" width="348" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use our Appwrite instance within our Flutter app, we need to connect our project to Appwrite. This process differs from the emulator's OS (Android or IOS).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;br&gt;
First, obtain the &lt;code&gt;bundle ID&lt;/code&gt; by going to the &lt;code&gt;project.pbxproj&lt;/code&gt; file (&lt;code&gt;ios &amp;gt; Runner.xcodeproj &amp;gt; project.pbxproj&lt;/code&gt;) and searching for the &lt;code&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, head to the &lt;code&gt;Runner.xcworkspace&lt;/code&gt; folder in the applications iOS folder in the project directory on &lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt;. To select the runner target, choose the Runner project in the Xcode project navigator and find the &lt;code&gt;Runner target&lt;/code&gt;. Then, select &lt;code&gt;General and IOS 11.0&lt;/code&gt; in the deployment info section as the target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;br&gt;
For Android, copy the XML script below and paste it below the activity tag in the &lt;code&gt;Androidmanifest.xml&lt;/code&gt; file (to find this file, head to &lt;code&gt;android &amp;gt; app &amp;gt; src &amp;gt; main&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: change [PROJECT-ID] to the ID used when creating the Appwrite project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Enabling Google OAuth2 provider&lt;/strong&gt;&lt;br&gt;
In order to use Google as a provider in Appwrite, we will need to have it enabled. To do this, we will head to &lt;strong&gt;Auth &amp;gt; Settings.&lt;/strong&gt; We will scroll to Google and check the enabled switch within the settings area. We are also required to fill in the App ID and secret, but we will do that later as we initially need to set up Google OAuth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting up Google OAuth 2.0&lt;/strong&gt;&lt;br&gt;
To set up, we will head to the Google &lt;a href="https://console.developers.google.com/" rel="noopener noreferrer"&gt;API console&lt;/a&gt; page and head to &lt;strong&gt;API and Services&lt;/strong&gt; within our project (we must create a new project if we do not have one).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6509g1sadatsm8pkv7fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6509g1sadatsm8pkv7fw.png" alt="api and services" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we select &lt;strong&gt;Credentials&lt;/strong&gt;, followed by clicking on &lt;strong&gt;CREATE CREDENTIALS&lt;/strong&gt;. Doing this will show a dropdown with some options, and we will proceed to select &lt;strong&gt;OAuth client ID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bdin996akqadvprn4a6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bdin996akqadvprn4a6.png" alt="credentials" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If it is your first time creating a client ID, you will need to configure your consent screen, which you won’t be required to do again after.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When creating a new OAuth Client ID, we will follow the configurations below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Type -&lt;/strong&gt; &lt;code&gt;Web Application&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name -&lt;/strong&gt; (choose preferred name)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorized JavaScript origins&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;URIs1 - &lt;a href="https://cloud.appwrite.io" rel="noopener noreferrer"&gt;https://cloud.appwrite.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;URIs2 - &lt;a href="https://localhost" rel="noopener noreferrer"&gt;https://localhost&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorized redirect URIs&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;URIs - paste URL from the Google OAuth provider provided by Appwrite&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feda9ed8zd8zfl0t7rym4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feda9ed8zd8zfl0t7rym4.png" alt="client id for web application" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After filling in the prompts on the page, we select save. Then we will get a splash screen showing our client ID and secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dyr8xj5ec2izz0tjdhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dyr8xj5ec2izz0tjdhj.png" alt="credentials" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will then head back to the Google OAuth provider page, paste in the Client ID and secret in the App ID and secret section, respectively, and click &lt;strong&gt;update&lt;/strong&gt;. That is all, and we have successfully enabled Appwrite as our OAuth2 client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google OAuth2 provider and Flutter&lt;/strong&gt;&lt;br&gt;
This project utilizes the &lt;code&gt;provider&lt;/code&gt; package for its state management. In the &lt;code&gt;util.dart&lt;/code&gt; file, we will create an &lt;code&gt;Appconstants&lt;/code&gt; class to serve as placeholders for some important constants, such as our Appwrite &lt;strong&gt;endpoint&lt;/strong&gt; and &lt;strong&gt;ProjectID&lt;/strong&gt;. Next, create a &lt;code&gt;ChangeNotifier&lt;/code&gt; class called AppProvider. This class initializes the client and account instance from Appwrite. Next, create a function called &lt;code&gt;socialSignIn&lt;/code&gt; which takes in the OAuth2 &lt;code&gt;provider&lt;/code&gt; as a string and context. This function will use the Account API to create a new OAuth2 session on Appwrite and run the condition that if an account is successfully created, it redirects to a new page by setting &lt;code&gt;_isLoggedin&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/appwrite.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:google_auth/screens/home.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Appconstants&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;endpoint or hostname&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;projectid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;project ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;late&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;AppProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;
      &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nf"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Appconstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projectid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nf"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Appconstants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;checkLogin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;checkLogin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;socialSignIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOAuth2Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this code from our &lt;code&gt;ChangeNotifier&lt;/code&gt; class, we will create a UI consisting of a button and an alternate screen called &lt;code&gt;Homepage&lt;/code&gt;, which we will route to after successfully running the &lt;code&gt;socialSignIn&lt;/code&gt; function. Therefore, in our &lt;code&gt;lib&lt;/code&gt; folder, create an alternate folder called &lt;code&gt;screens&lt;/code&gt; and create two files in it, &lt;code&gt;user_reg.dart&lt;/code&gt; and &lt;code&gt;home.dart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;user_reg.dart&lt;/code&gt; screen’s UI will contain an elevated button in which its &lt;code&gt;onPressed&lt;/code&gt; property triggers the &lt;code&gt;socialSignIn&lt;/code&gt; function in the &lt;code&gt;ChangeNotifier&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:google_auth/util.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:provider/provider.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRegistration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;UserRegistration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRegistration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;_UserRegistrationState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_UserRegistrationState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRegistration&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BuildContext&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;appBar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IntrinsicWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;EdgeInsets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blueGrey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BorderRadius&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Radius&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="na"&gt;onPressed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socialSignIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g_mobiledata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sign in with Google&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;home.dart&lt;/code&gt; file, we will have a &lt;code&gt;StatefulWidget&lt;/code&gt; called Homepage consisting of text at the center of the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Homepage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Homepage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Homepage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;_HomepageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_HomepageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Homepage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BuildContext&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run the app, we should have our results as below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3siucqecvae9yzhjkzx6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3siucqecvae9yzhjkzx6.gif" alt="result" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This post showed how to use Google as a provider using Appwrite as an OAuth client. Appwrite utilizes Google as a provider and serves as a client for 35 more providers. Thus, creating a vast plain of knowledge to explore. &lt;/p&gt;

&lt;p&gt;Here are some resources to aid the learning journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://appwrite.io/docs/authentication#oauth" rel="noopener noreferrer"&gt;Appwrite OAuth support&lt;/a&gt;
&lt;a href="https://hackmamba.io/blog/2023/02/how-to-quickly-add-github-login-to-your-flutter-application/" rel="noopener noreferrer"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackmamba.io/blog/2023/02/how-to-quickly-add-github-login-to-your-flutter-application/" rel="noopener noreferrer"&gt;How to Quickly Add GitHub Login to your Flutter Application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>authentication</category>
      <category>appwrite</category>
      <category>flutter</category>
      <category>google</category>
    </item>
    <item>
      <title>SMS authentication using Appwrite and Twilio</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Tue, 05 Sep 2023 22:36:47 +0000</pubDate>
      <link>https://dev.to/hackmamba/how-to-set-up-twilio-in-appwrite-398o</link>
      <guid>https://dev.to/hackmamba/how-to-set-up-twilio-in-appwrite-398o</guid>
      <description>&lt;p&gt;When checking out an app or service, it is exhilarating, but it can also be deflating when asked to sign up to access significant parts of that service. We can attribute this sudden change in emotions to the tedious steps associated with the user sign-up process. &lt;/p&gt;

&lt;p&gt;Though tedious, most sign-up procedures are necessary as they ensure the safety of the user's personal information. Let's face it; no one likes knowing their personal information is easily accessible to others, right? But come to think of it, what if there is an option where we don't have to provide much information while maintaining user information security? We like that option much better!&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite&lt;/a&gt;, developers can integrate several authentication features into their applications with its diverse APIs and features. One feature that catches the eye is phone authentication, which uses &lt;a href="https://appwrite.io/docs/client/account?sdk=flutter-default"&gt;Appwrite's Account API&lt;/a&gt; to create user sessions with phone numbers. This feature's authentication flow involves sending a secret code (one-time password) via an SMS provider such as &lt;strong&gt;Twilio, TextMagic, Telesign, MSG91, or Vonage&lt;/strong&gt;. This article will use &lt;a href="https://www.twilio.com/en-us?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Twilio&lt;/a&gt; as our primary SMS provider and show how to set it up in Appwrite.&lt;/p&gt;

&lt;p&gt;This article requires the reader to have a &lt;a href="https://www.twilio.com/try-twilio?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Twilio account&lt;/a&gt;, iOS Simulator, Android Studio, or Chrome web browser to test their application, and an Appwrite instance running on Docker, &lt;a href="https://marketplace.digitalocean.com/apps/appwrite"&gt;&lt;/a&gt;&lt;a href="https://marketplace.digitalocean.com/apps/appwrite"&gt;DigitalOcean droplet&lt;/a&gt;, or &lt;a href="https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod"&gt;Gitpod&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Check out this &lt;a href="https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9"&gt;article&lt;/a&gt; to learn how to set up an Appwrite instance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setting up Twilio in Appwrite
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Getting Twilio account information&lt;/strong&gt;&lt;br&gt;
The purpose of creating a Twilio account is to allow us to have three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Account SID&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Token&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Twilio Phone Number&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After logging in, we will need to follow the welcome steps, which guide us on how to get a custom Twilio number. In the first step, we will click on &lt;strong&gt;Get Twilio Phone Number&lt;/strong&gt;, then scroll down to copy the information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GXI3mo0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692602072089_Twilo%2BSnip_new1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GXI3mo0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692602072089_Twilo%2BSnip_new1.png" alt="welcome 1" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YHkK2s3S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692602072030_Twilo%2BSnip_new2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YHkK2s3S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692602072030_Twilo%2BSnip_new2.png" alt="welcome 2" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After copying the account information, we must update Appwrite's &lt;code&gt;.env&lt;/code&gt; file with the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updating Appwrite's environmental variables&lt;/strong&gt;&lt;br&gt;
We will head to our PC's Appwrite directory and update the &lt;code&gt;.env&lt;/code&gt; file by giving the &lt;code&gt;_APP_SMS_PROVIDER&lt;/code&gt; and &lt;code&gt;_APP_SMS_FROM&lt;/code&gt; variables the values &lt;code&gt;sms://[ACCOUNT SID]:[AUTH TOKEN]@twilio&lt;/code&gt; and &lt;code&gt;[TWILIO PHONE NUMBER]&lt;/code&gt; respectively. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2iZlc2QY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1691938295718_environmental%2Bvariables.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2iZlc2QY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1691938295718_environmental%2Bvariables.PNG" alt="Environmental variable" width="659" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, it is important to restart the Appwrite server after updating the &lt;code&gt;.env&lt;/code&gt; file. This allows us to use the environmental variables added to the file, and we can do this using the command &lt;code&gt;docker compose up -d --force-recreate&lt;/code&gt; in a terminal. The command recreates every image within the Appwrite container running on docker.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The docker service must be running, and make sure to run the command terminal within the directory of the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are now ready to utilize Twilio to create our phone authentication. Thus, in the next section, we will create a Flutter application that routes to the homepage after authenticating a user's phone number. But first, we need to create an Appwrite project; Thus, head to the browser and enter the &lt;code&gt;IP address or hostname&lt;/code&gt; specified when creating the Appwrite instance. Next, we must create a new project by clicking &lt;code&gt;Create Project&lt;/code&gt; and filling in the project name and ID (optional).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cRdlGi3e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093051889_create%2Bproject.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cRdlGi3e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093051889_create%2Bproject.PNG" alt="Create project" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a Flutter project&lt;/strong&gt;&lt;br&gt;
In this article, we will use a Flutter template consisting of a login page with input fields, a submit button, and a homepage to route to after authentication. Therefore, run the command below in a terminal to clone the Flutter project from GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/muyiwexy/main_twilio_auths.git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: Check out the official GitHub &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository"&gt;docs&lt;/a&gt; to learn about cloning a repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After cloning the UI, we must obtain all the dependencies in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file, or there will be "some" errors. So, we can do that with the command &lt;code&gt;flutter pub get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The project already has the &lt;code&gt;appwrite: ^9.0.1&lt;/code&gt; dependency, though, for a new project, we need to head to the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and add the &lt;code&gt;appwrite: ^9.0.1&lt;/code&gt; to the dependencies section. Then run the &lt;code&gt;flutter pub get&lt;/code&gt; command or save the file, and the command runs automatically (depending on the code editor).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qDCC-p-7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692005094421_pubspec%2Bfile.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qDCC-p-7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692005094421_pubspec%2Bfile.PNG" alt="pubspec file" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run the project, we can use the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Flutter&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After that, our template should look like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8gqarlA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1691946762728_emulator.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8gqarlA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1691946762728_emulator.PNG" alt="emulator" width="410" height="904"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This template is a husk, but it will come to life in the next section as we work on adding some functionality to the application and connecting it to Appwrite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating phone authentication&lt;/strong&gt; &lt;strong&gt;logic&lt;/strong&gt;&lt;br&gt;
In the &lt;code&gt;appwrite_auth.dart&lt;/code&gt; file, we will create a class &lt;code&gt;AppwriteAuth,&lt;/code&gt; and within it, we need to initialize the &lt;strong&gt;Client&lt;/strong&gt; instance from Appwrite.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/appwrite.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[endpoint or hostname]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[projectID]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, we will create a &lt;code&gt;Future&lt;/code&gt; function of type &lt;code&gt;Token&lt;/code&gt; called &lt;code&gt;phoneLogin&lt;/code&gt;. The function uses Appwrite's account API to create a session using a user's phone number by providing a phone number and ID.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/appwrite.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/models.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[endpoint or hostname]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[projectID]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;phoneLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createPhoneSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The function above only creates a user session, which triggers sending the secret token but doesn't verify the user. To verify the user, we will create another &lt;code&gt;Future&lt;/code&gt; function of type &lt;code&gt;Session&lt;/code&gt; called &lt;code&gt;verifyPhoneOTP&lt;/code&gt;. The &lt;code&gt;Future&lt;/code&gt; also utilizes Appwrite's account API to update a session rather than create one. This means we must provide the user's ID to check whether such a user exists and the secret token sent to verify the user. This completes our authentication flow.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/appwrite.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/models.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[endpoint or hostname]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;setProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[projectID]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;phoneLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;verifyPhoneOTP&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;otp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatePhoneSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;otp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;rethrow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To use this function,  head to the &lt;code&gt;user_registraton.dart&lt;/code&gt; file and update the &lt;code&gt;_createUserSession&lt;/code&gt; with the code below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/models.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/auth/appwrite_auth.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/pages/home.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/widgets/button.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/widgets/input_form_field.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;UserLogIn&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
      &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_UserLogInState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;_UserLogInState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt; &lt;span class="nx"&gt;_phoneController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt; &lt;span class="nx"&gt;_otpTokenController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;GlobalKey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_formKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GlobalKey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="nx"&gt;_isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;_response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;_createUserSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_formKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;phoneLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_phoneController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;_isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
      &lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BuildContext&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the code above, we added a &lt;code&gt;Token&lt;/code&gt; instance &lt;code&gt;_response&lt;/code&gt; from the Appwrite's models package. This allows us to map the JSON response received from its associated value to a model class, and that's shown when we call the &lt;code&gt;phoneLogin&lt;/code&gt; function in the code above.&lt;/p&gt;

&lt;p&gt;Next, we will update the &lt;code&gt;_updateUserSession&lt;/code&gt; with the code below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:appwrite/models.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:flutter/material.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/auth/appwrite_auth.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/pages/home.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/widgets/button.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package:main_twilio_auth/widgets/input_form_field.dart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;UserLogIn&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_UserLogInState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;_UserLogInState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserLogIn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt; &lt;span class="nx"&gt;_phoneController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt; &lt;span class="nx"&gt;_otpTokenController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TextEditingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;GlobalKey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_formKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;GlobalKey&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="nx"&gt;_isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;bool&lt;/span&gt; &lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;_response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;_createUserSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;_updateUserSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_formKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;verifyPhoneOTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="na"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_response&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;otp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_otpTokenController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pushReplacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MaterialPageRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;_phoneController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;_otpTokenController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;override&lt;/span&gt;
  &lt;span class="nx"&gt;Widget&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BuildContext&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Placeholder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This function calls the &lt;code&gt;verifyPhoneOTP&lt;/code&gt; from the &lt;code&gt;AppwriteAuth&lt;/code&gt; class, checks if the current widget is still mounted, then routes by replacing the &lt;code&gt;UserLogIn&lt;/code&gt; widget with the &lt;code&gt;HomePage&lt;/code&gt; widget on the widget tree.&lt;/p&gt;

&lt;p&gt;When we don't get the secret token due to some factors, the "&lt;strong&gt;send otp&lt;/strong&gt;" button triggers a function &lt;code&gt;reSendOtp&lt;/code&gt; which recalls the &lt;code&gt;phoneLogin&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;_sendOtp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppwriteAuth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;phoneLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_phoneController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;_isButtonDisabled&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Creating an Appwrite platform and connecting Flutter to Appwrite&lt;/strong&gt;&lt;br&gt;
After creating an Appwrite project, we will register our application by creating a new Flutter platform within the Appwrite instance. So, we will click &lt;code&gt;Flutter App&lt;/code&gt;, select our desired operating system (in this case, Android), and fill in the &lt;code&gt;Name and Package Name&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The app's package name can be found in the app-level &lt;code&gt;build.gradle&lt;/code&gt; file&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NSYgF-Bn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093618891_Flutter%2Bapp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NSYgF-Bn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093618891_Flutter%2Bapp.png" alt="Flutter platform" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iVA-BcUr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093627277_android.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iVA-BcUr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692093627277_android.png" alt="Android Flutter Platform" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;br&gt;
First, obtain the &lt;code&gt;bundle ID&lt;/code&gt; by navigating to the &lt;code&gt;project.pbxproj&lt;/code&gt; file (&lt;code&gt;ios &amp;gt; Runner.xcodeproj &amp;gt; project.pbxproj&lt;/code&gt;) and searching for the &lt;code&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, head to the &lt;code&gt;Runner.xcworkspace&lt;/code&gt; folder in the application's iOS folder in the project directory on &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt;. To select the runner target, choose the &lt;strong&gt;Runner&lt;/strong&gt; project in the Xcode project navigator and find the &lt;code&gt;Runner target&lt;/code&gt;. Next, select &lt;code&gt;General and IOS 11.0&lt;/code&gt; as the targeting of the deployment info section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_8YrpswT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_8YrpswT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" alt="iOS" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;br&gt;
For Android, copy the XML script below and paste it below the activity tag in the &lt;code&gt;Androidmanifest.xml&lt;/code&gt; file (to find this file, head to &lt;code&gt;android &amp;gt; app &amp;gt; src &amp;gt; main&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, running the application should have our result like the gif below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QPwqRSTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692092303060_twilio_messaging_gif.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QPwqRSTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_673FB39A2A8C2B8C74123855FD7FA3D297D922219CCB3C496E5097DB64711AD1_1692092303060_twilio_messaging_gif.gif" alt="Result" width="508" height="1080"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This tutorial has shown how to create a phone authentication in Flutter using &lt;a href="https://appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite&lt;/a&gt; as the backend service and &lt;a href="https://www.twilio.com/en-us?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Twilio&lt;/a&gt; as an SMS provider. Authentication is a focal point in app development, and innovations to simplify the process are always happening. Appwrite has simplified this process by cutting the extra work of creating an SMTP flow or token, which is just cumbersome to a simple copy-and-paste job while ensuring user data security data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/hackmamba/the-benefits-of-using-appwrite-cloud-for-your-authentication-needs-4m90"&gt;The benefits of using Appwrite Cloud for your authentication needs&lt;/a&gt;
&lt;a href="https://dev.to/hackmamba/a-beginners-guide-to-oauth-20-with-google-sign-in-enhance-android-app-authentication-2mhi"&gt;&lt;/a&gt;- &lt;a href="https://dev.to/hackmamba/a-beginners-guide-to-oauth-20-with-google-sign-in-enhance-android-app-authentication-2mhi"&gt;A beginner's guide to OAuth 2.0 with Google sign-in: Enhance Android app authentication&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/appwrite/phone-authentication-with-appwrite-and-vonage-1ep0"&gt;Phone Authentication with Appwrite and Vonage&lt;/a&gt;
&lt;a href="https://dev.to/hackmamba/the-benefits-of-using-appwrite-cloud-for-your-authentication-needs-4m90"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>appwrite</category>
      <category>twilio</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Build fast with Appwrite Cloud: accelerate your web, mobile, and Flutter development</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Wed, 12 Jul 2023 13:33:03 +0000</pubDate>
      <link>https://dev.to/hackmamba/build-fast-with-appwrite-cloud-accelerate-your-web-mobile-and-flutter-development-24co</link>
      <guid>https://dev.to/hackmamba/build-fast-with-appwrite-cloud-accelerate-your-web-mobile-and-flutter-development-24co</guid>
      <description>&lt;p&gt;Speed is crucial for prototyping, building, and deploying modern-day web and mobile applications. This necessity has led to a vast increase in third-party tools providing various services like authentication, storage, and emails which have all helped developers scale more quickly. While these tools have effectively delivered faster results, implementing, maintaining, and tracking multiple third-party tools in an application can be challenging and time-consuming, leaving room for errors. With speed as the aim, having a service that combines the capacity of a backend and third-party tools will come in handy.&lt;/p&gt;

&lt;p&gt;This article introduces Appwrite cloud, which offers a nearly unlimited amount of possibilities for scaling and accelerates the development process of your mobile, web, and Flutter applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appwrite Cloud features
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cloud.appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite Cloud&lt;/a&gt; takes being capable to a whole new level by providing backend functionalities to your mobile, web, and Flutter applications. Here are some of the capabilities of Appwrite Cloud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Authentication and Integration with third-party services&lt;/li&gt;
&lt;li&gt;Database Management&lt;/li&gt;
&lt;li&gt;File Storage and Management&lt;/li&gt;
&lt;li&gt;Real-time Communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;User authentication and integration with third-party services&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud provides easy and scalable ways to implement secure &lt;a href="https://appwrite.io/docs/client/account?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;user authentication&lt;/a&gt;, login, and registration in your applications. User data is kept safe through Appwrite's effort to employ a safety mechanism that protects data during transmission and when at rest. Appwrite Cloud's compliance with regulations like GDPR (General Data Protection Regulation) ensures that your applications meet a required data privacy standard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database management&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://appwrite.io/docs/client/databases?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Database management&lt;/a&gt; is essential to a modern-day backend and Appwrite Cloud accomplishes it like no other. It allows you to perform the basic CRUD (create, read, update, and delete) operations of a traditional database and other advanced database operations by providing a NoSQL document-based database. It offers flexibility and scalability when storing and managing structured data, thus, enabling efficient data management and querying for your applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File storage and management&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://appwrite.io/docs/client/storage?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;File storage&lt;/a&gt;, versioning, control, and generation have become efficient using Appwrite Cloud. Appwrite Cloud includes a scalable file storage system that allows you to upload, store, and manage images, videos, and document files. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-time communication&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud allows your activities to come to life in real-time. "&lt;a href="https://appwrite.io/docs/realtime?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Real-time&lt;/a&gt;" is a feature that uses WebSocket, allowing instant sharing and data synchronization across multiple clients. Consider it: collaborative features like live chats, updates, and editing all come to life using Appwrite Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of using Appwrite Cloud for fast development
&lt;/h2&gt;

&lt;p&gt;When it comes to assisting developers in rapid iterating and prototyping, Appwrite Cloud offers several benefits, like the provision of prebuilt components and SDKs, scalability and performance optimization, and simple hosting and deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prebuilt components and SDKs&lt;/strong&gt;&lt;br&gt;
The features mentioned earlier assist in streamlining development by providing prebuilt features to the developers. For example, developers can quickly integrate user authentication into their prototypes using &lt;strong&gt;Appwrite Cloud Account API&lt;/strong&gt; rather than creating user authentication from scratch. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability and performance optimi&lt;/strong&gt;&lt;strong&gt;z&lt;/strong&gt;&lt;strong&gt;ation&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud also eliminates &lt;a href="https://dev.to/hackmamba/breaking-through-growth-barriers-how-appwrites-cloud-enables-scalability-1f57"&gt;scalability&lt;/a&gt; &lt;a href="https://dev.to/hackmamba/breaking-through-growth-barriers-how-appwrites-cloud-enables-scalability-1f57"&gt;&lt;/a&gt;and performance-related concerns by being designed to upscale simultaneously with the application's growth. Therefore, you can rely on Appwrite's infrastructure to ensure your prototype performs as expected, thus, allowing you to focus better on the user experience side of things during the iteration stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple hosting and deployment&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud provides seamless deployment and hosting options while eliminating the need to manage servers and infrastructures. This option enables rapid testing and iteration, thus, making it easy and quick for you to share your prototype with clients for feedback. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is the need for eliminating server and infrastructure management a big deal?&lt;/strong&gt; &lt;br&gt;
Imagine you must build a house (your application) and need a piece of land (server infrastructure) to achieve the goal. Typically, you must find and prepare the land (plumbing, stump removal, and secondary electricity), which can be quite tasking.&lt;br&gt;
In this case, Appwrite Cloud is like ready-made ground; you only have to build on it. The level of effectiveness doesn't just make Appwrite Cloud time-efficient but borderline cost-effective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boosting web and app development with Appwrite Cloud
&lt;/h2&gt;

&lt;p&gt;Appwrite Cloud doesn't only boost development time but also lets you expand faster by providing the following capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-platform compatibility&lt;/li&gt;
&lt;li&gt;Effortless data synchronization&lt;/li&gt;
&lt;li&gt;Integration with popular web and app frameworks&lt;/li&gt;
&lt;li&gt;Push notifications and in-app messaging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform compatibility&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud supports cross-platform development, allowing developers to build web and mobile applications (IOS and Android) using the same codebase. This advantage saves time and boosts developers' efficiency by enabling them to write and deploy code quickly across different platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effortless data synchroni&lt;/strong&gt;&lt;strong&gt;z&lt;/strong&gt;&lt;strong&gt;ation&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud's "real-time" feature lets you easily synchronize data between your mobile, web applications, and the backend server. Changes made on one device are automatically reflected on other devices, allowing users to have up-to-date information regardless of their device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integration with popular web and app frameworks&lt;/strong&gt;&lt;br&gt;
Appwrite Cloud integrates with several web and mobile frameworks for development, such as Flutter. Flutter is a cross-platform UI toolkit that lets developers build web, mobile, and desktop applications using a single codebase. Appwrite Cloud provides backend integration for this framework by providing ready-to-use SDKs and components, accelerating development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Push notifications and in-app messaging&lt;/strong&gt;&lt;br&gt;
Through server-side functions, you can add a custom function to perform a specific operation once a user is within the application. Such operations are push notifications and in-app messaging. These sorts of functions facilitate personalized interactions and improve the user's overall experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving Flutter development with Appwrite Cloud
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, Flutter is a cross-platform UI toolkit for web, mobile, and desktop applications. Flutter also provides a native-like performance, thus, giving it this silky smooth experience. Appwrite Cloud seamlessly integrates with a Flutter application's interface, enabling a fast response between the client and the backend. This interaction extends to simple features like the hot reload, which instantly allows developers to see the changes made in their code without rebuilding the entire app.&lt;/p&gt;

&lt;p&gt;Appwrite Cloud provides Flutter applications with secure authentication and data storage. It offers robust encryption and data protection mechanism using secure communication protocols, such as HTTPS (HTTP over SSL/TLS). This communication protocol ensures that data transmitted between your app and the backend servers is encrypted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Appwrite Cloud
&lt;/h2&gt;

&lt;p&gt;To use Appwrite Cloud for your mobile, web, and Flutter development, follow the steps below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by creating a new account on the &lt;a href="https://cloud.appwrite.io/register"&gt;Appwrite Cloud&lt;/a&gt; platform. You can register with your email and password or via a GitHub account.&lt;/li&gt;
&lt;li&gt;After signing up, you will get redirected to the onboarding page to create a new project. Fill in the project name and ID, then select &lt;strong&gt;&lt;em&gt;Create Project&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt; Congrats, you have successfully created an Appwrite Cloud account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Appwrite also provides the documentation needed to get you started with their APIs and components. Head to the &lt;a href="https://appwrite.io/docs?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;docs&lt;/a&gt; section of their website to get started.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://appwrite.io/public-beta?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite's latest community post by Christy Jacob&lt;/a&gt;, they are currently working on a pricing model to benefit small and large organizations and independent programmers. They also announced they would include a free tier to appeal to hobby project developers. So, sit tight and get ready to create.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In summary, Appwrite Cloud epitomizes effectiveness, speed, and cost efficiency. It provides developers with the necessary tools to scale up their web, mobile, and Flutter applications by providing components of a traditional backend and third-party tools all in one package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/hackmamba/scalability-what-every-business-using-the-cloud-needs-to-know-54ci"&gt;&lt;strong&gt;Scalability: What every business using the cloud needs to know&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/hackmamba/building-trust-in-baas-platforms-the-essential-guide-to-better-data-management-ba5"&gt;&lt;strong&gt;Building Trust in BaaS Platforms: The Essential Guide to Better Data Management&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/hackmamba/how-this-baas-platform-is-pushing-the-boundaries-of-scalable-data-storage-3m8l"&gt;&lt;strong&gt;How This BaaS Platform Is Pushing the Boundaries of Scalable Data Storage&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>marketing</category>
      <category>flutter</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>How to build a functional food delivery tracker app with Appwrite relationship database and Flutter</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Wed, 14 Jun 2023 14:12:25 +0000</pubDate>
      <link>https://dev.to/hackmamba/how-to-build-a-functional-food-delivery-tracker-app-with-appwrite-relationship-database-and-flutter-4go3</link>
      <guid>https://dev.to/hackmamba/how-to-build-a-functional-food-delivery-tracker-app-with-appwrite-relationship-database-and-flutter-4go3</guid>
      <description>&lt;p&gt;Food delivery is one of the most prominent businesses in the digital age. Companies like Uber Eats, Jumia, Mano, etc. have applications to track customers’ orders, and in turn, the customer can view the delivery process of their products. These features can be enabled by establishing a Relationship in databases, thus creating relationships between order and delivery.&lt;/p&gt;

&lt;p&gt;With Appwrite, you can now use such features in your project. Thus, this article will demonstrate how to create a functional delivery tracker application using the &lt;a href="https://appwrite.io/docs/databases-relationships?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite relationship database&lt;/a&gt; and Flutter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we’ll cover:&lt;/strong&gt;&lt;br&gt;
A food delivery tracker application should offer the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create user’s order&lt;/li&gt;
&lt;li&gt;View the user’s order&lt;/li&gt;
&lt;li&gt;Confirm the order’s delivery&lt;/li&gt;
&lt;li&gt;Cancel the user’s order and delivery.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This tutorial requires the reader to meet the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt; (with developer account for Mac users).&lt;/li&gt;
&lt;li&gt;iOS Simulator, Android Studio, or Chrome web browser to run the application.&lt;/li&gt;
&lt;li&gt;An Appwrite instance running on either Docker, &lt;a href="https://marketplace.digitalocean.com/apps/appwrite" rel="noopener noreferrer"&gt;DigitalOcean droplet&lt;/a&gt;, or &lt;a href="https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod" rel="noopener noreferrer"&gt;Gitpod&lt;/a&gt;. Check out this &lt;a href="https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9"&gt;article&lt;/a&gt; for the setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Setting up the Appwrite project
&lt;/h2&gt;

&lt;p&gt;Appwrite’s relationship database feature is currently only available locally; thus, you must have an Appwrite local instance running on &lt;a href="https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9"&gt;Docker&lt;/a&gt; or &lt;a href="https://marketplace.digitalocean.com/apps/appwrite" rel="noopener noreferrer"&gt;DigitalOcean droplet.&lt;/a&gt; Once you have this, create a project and fill in the &lt;strong&gt;project's name and ID.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpr9v8xewexmaqw03h1up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpr9v8xewexmaqw03h1up.png" alt="Create project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to create multiple database collection pairs during this project. The first pair will be between &lt;strong&gt;vendors → foodtype&lt;/strong&gt;, and the second pair &lt;strong&gt;order → delivery&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Head to Databases, select &lt;strong&gt;Create Database&lt;/strong&gt;, and fill in the database &lt;strong&gt;name and ID&lt;/strong&gt;. After, create a new collection by selecting &lt;strong&gt;Create collection&lt;/strong&gt; and filling in the subsequent &lt;strong&gt;name and ID&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffttywkdxfgfbhgqp0b7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffttywkdxfgfbhgqp0b7m.png" alt="database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof0ldpasyw0fkwnoawaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof0ldpasyw0fkwnoawaj.png" alt="Create database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zpvx3cp8njq5e6fop92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8zpvx3cp8njq5e6fop92.png" alt="Create collection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you need to add some attributes as they will serve as parameters to hold data within your collection. To add an attribute to a particular collection, head to any of your newly created collections, select &lt;strong&gt;Create attribute&lt;/strong&gt; and select any of your preferred attribute types from the available options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69nwbgf89lnl8jtlmpfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69nwbgf89lnl8jtlmpfu.png" alt="create attribute"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, add the attributes below to the &lt;strong&gt;vendors&lt;/strong&gt; collection:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;key&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foodTypes&lt;/td&gt;
&lt;td&gt;Relationship with &lt;strong&gt;foodTypes&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;foodtype&lt;/strong&gt; collection will have the following attributes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;key&lt;/th&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;foodtype&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;food&lt;/td&gt;
&lt;td&gt;String []&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foodChecked&lt;/td&gt;
&lt;td&gt;Boolean []&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relationship attribute between the &lt;strong&gt;vendors → foodtype&lt;/strong&gt; has the following settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One-way relationship&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Related Collection → &lt;strong&gt;vendor&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attribute Key → &lt;strong&gt;vendors&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attribute Key (related collection) → &lt;strong&gt;foodTypes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Relation → &lt;strong&gt;many to many&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;On deleting a document → &lt;strong&gt;set Null&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the second pair, the order collection has the following attributes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;key&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;vendorName&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;orderStatus&lt;/td&gt;
&lt;td&gt;Enum(&lt;strong&gt;in-transit, payment-acepted, packed, delivered, canceled, not-delivered&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;payment-acepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;orderTime&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foodItems&lt;/td&gt;
&lt;td&gt;String []&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delivery&lt;/td&gt;
&lt;td&gt;Relationship with &lt;strong&gt;delivery&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The delivery collection has the following attributes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;key&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OrderID&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deliveryStatus&lt;/td&gt;
&lt;td&gt;Enum (&lt;strong&gt;in-progress, completed, failed&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;in-progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deliveryTime&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;order&lt;/td&gt;
&lt;td&gt;Relationship with &lt;strong&gt;order&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relationship attribute between the &lt;strong&gt;order → delivery&lt;/strong&gt; has the following settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Two-way relationship&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Related Collection → &lt;strong&gt;delivery&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attribute Key → &lt;strong&gt;delivery&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attribute Key (related collection) → &lt;strong&gt;order&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Relation → &lt;strong&gt;one to one&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;On deleting a document → &lt;strong&gt;cascading&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, head to the collection settings section and set the collection level permission to &lt;code&gt;role:any&lt;/code&gt; and check the &lt;code&gt;read&lt;/code&gt; CRUD permissions &lt;strong&gt;vendors → foodtype&lt;/strong&gt; pair. For the &lt;code&gt;order → delivery&lt;/code&gt; pair, set the collection level permission to &lt;code&gt;role:user&lt;/code&gt; and check all the CRUD permissions&lt;/p&gt;

&lt;p&gt;These permissions allow anyone to create, read, update, and delete documents from the collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8xol37nt5jm9qzfb1my.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8xol37nt5jm9qzfb1my.png" alt="permission"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1zi7yzi49khbh3gf2al.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1zi7yzi49khbh3gf2al.png" alt="permission2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding data to the Vendor and Foodtype collection&lt;/strong&gt;&lt;br&gt;
Next, you can add sample data by heading to the &lt;strong&gt;Documents&lt;/strong&gt; tab and clicking &lt;strong&gt;Add Documents,&lt;/strong&gt; populating the fields available and clicking &lt;strong&gt;Create.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vendor&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;document&lt;/th&gt;
&lt;th&gt;vendorName&lt;/th&gt;
&lt;th&gt;foodTypes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;document 1&lt;/td&gt;
&lt;td&gt;Karic’s&lt;/td&gt;
&lt;td&gt;[document 1, document 2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;document 2&lt;/td&gt;
&lt;td&gt;Mecurial&lt;/td&gt;
&lt;td&gt;[document 2]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Foodtype&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;document&lt;/th&gt;
&lt;th&gt;foodtype&lt;/th&gt;
&lt;th&gt;food&lt;/th&gt;
&lt;th&gt;foodChecked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;document 1&lt;/td&gt;
&lt;td&gt;African&lt;/td&gt;
&lt;td&gt;[“Eba”, “Semo”]&lt;/td&gt;
&lt;td&gt;[false, false]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;document 2&lt;/td&gt;
&lt;td&gt;Rice-dish&lt;/td&gt;
&lt;td&gt;[“Jollof”, “Fried rice”]&lt;/td&gt;
&lt;td&gt;[false, false]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683235918856_Screenshot%2B303.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683235918856_Screenshot%2B303.png" alt="adding data"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Cloning the UI template
&lt;/h2&gt;

&lt;p&gt;This section uses a UI template containing user registration and login code. Let’s clone the &lt;a href="https://github.com/muyiwexy/delivery_tracker" rel="noopener noreferrer"&gt;repository&lt;/a&gt; specified in the prerequisites. Check out the official GitHub &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository" rel="noopener noreferrer"&gt;docs&lt;/a&gt; to learn more about cloning a repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbefvm2clcodpofxhnrm5.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbefvm2clcodpofxhnrm5.PNG" alt="clone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After cloning the UI to your PC, open it in your preferred code editor and run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command obtains all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies. Next, run the command &lt;code&gt;flutter run&lt;/code&gt;, and your application should look like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683062163209_Screenshot%2B300.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683062163209_Screenshot%2B300.png" alt="clone result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lib&lt;/code&gt; directory tree should look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;app_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;order_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;user_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;vendor_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;HomeComponent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;first_column_item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;second_column_item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;registrationloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view_one_modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view_one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view_three&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;view_two&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;signup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Connecting a Flutter project to Appwrite
&lt;/h2&gt;

&lt;p&gt;Here’s how to connect a Flutter project to Appwrite for Android and iOS devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;br&gt;
First, obtain the &lt;code&gt;bundle ID&lt;/code&gt; by navigating to the &lt;code&gt;project.pbxproj&lt;/code&gt; file (&lt;code&gt;ios &amp;gt; Runner.xcodeproj &amp;gt; project.pbxproj&lt;/code&gt;) and searching for the &lt;code&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, head to the &lt;code&gt;Runner.xcworkspace&lt;/code&gt; folder in the application’s iOS folder in the project directory on &lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt;. To select the runner target, choose the &lt;strong&gt;Runner&lt;/strong&gt; project in the Xcode project navigator and find the &lt;code&gt;Runner target&lt;/code&gt;. Next, select &lt;code&gt;General and IOS 11.0&lt;/code&gt; in the deployment info section as the target.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" alt="ios"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;br&gt;
For Android, copy the XML script below and paste it below the activity tag in the &lt;code&gt;Androidmanifest.xml&lt;/code&gt; file (to find this file, head to &lt;code&gt;android &amp;gt; app &amp;gt; src &amp;gt; main&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will also need to set up a platform within the Appwrite console. Follow the steps below to do so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Within the Appwrite console, select &lt;code&gt;Create Platform&lt;/code&gt; and choose &lt;code&gt;Flutter&lt;/code&gt; for the platform type.&lt;/li&gt;
&lt;li&gt;Specify the operating system: in this case, Android.&lt;/li&gt;
&lt;li&gt;Finally, provide the application and package names (found in the app-level &lt;code&gt;build.gradle&lt;/code&gt; file).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Explaining the UI and Functionalities
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Functionalities&lt;/strong&gt;&lt;br&gt;
Start by creating a folder called &lt;code&gt;appConstants&lt;/code&gt; in the &lt;code&gt;lib&lt;/code&gt; folder, and within the folder, create the &lt;code&gt;app_constants.dart&lt;/code&gt; file. This file will store some important constants for the project in an &lt;code&gt;Appconstants&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Appconstants&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;projectid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;projectID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;cloud endpoint&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;dbID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;database ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;ordercollectionID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;collection ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;ordercollectionID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;collection ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The project uses the Provider package for state management, hence the &lt;code&gt;ChangeNotifier&lt;/code&gt; class in the &lt;code&gt;app_provider.dart&lt;/code&gt; file. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The user registration methods will not be the focal point of this article. You can do well to check out the syntax used in the method for personal learning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;ChangeNotifier&lt;/code&gt; class will retrieve the list of vendors and orders, create new user orders and update the order and delivery status. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;user_model.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;vendor_model.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;order_model.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;app_provider.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;In the code above, the &lt;code&gt;ChangeNotifier&lt;/code&gt; class consists of several instance variables such as Appwrite’s &lt;code&gt;client&lt;/code&gt;, &lt;code&gt;account&lt;/code&gt; and &lt;code&gt;databases&lt;/code&gt; instance, &lt;code&gt;_vendorItems&lt;/code&gt;, &lt;code&gt;_orderItems&lt;/code&gt; and, &lt;code&gt;_user&lt;/code&gt; model classes and &lt;code&gt;_isLoading&lt;/code&gt; boolean. It uses the &lt;code&gt;AppProvider&lt;/code&gt; class constructor to initialize the &lt;code&gt;_isLoading&lt;/code&gt; variable to &lt;code&gt;true&lt;/code&gt;, set the &lt;code&gt;_user&lt;/code&gt; variable to &lt;code&gt;null&lt;/code&gt;, and call the &lt;code&gt;initialize()&lt;/code&gt; method. &lt;/p&gt;

&lt;p&gt;It then sets the endpoint and project ID for the &lt;code&gt;client&lt;/code&gt; instance, creates an &lt;code&gt;Account&lt;/code&gt; object, and sets the &lt;code&gt;databases&lt;/code&gt; instance variable in the &lt;code&gt;initialize()&lt;/code&gt; method. It also calls the &lt;code&gt;checkUserSignIn()&lt;/code&gt; method, which tries to get the user account info using the &lt;code&gt;_getUseraccountInfo()&lt;/code&gt; method. If the &lt;code&gt;checkUserSignIn()&lt;/code&gt; method throws an error, it calls the &lt;code&gt;listVendorDocument()&lt;/code&gt; method to list the vendor document. This is because there is no available user session at that moment.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_getUseraccountInfo()&lt;/code&gt; tries to check whether a recent user session is available using the &lt;code&gt;account.get()&lt;/code&gt; method. If true, it maps the &lt;code&gt;JSON&lt;/code&gt; to the &lt;code&gt;User&lt;/code&gt; model class. It lists the vendor and order documents using the &lt;code&gt;listVendorDocument()&lt;/code&gt; and &lt;code&gt;listOrderDocument()&lt;/code&gt; methods, respectively, while setting the &lt;code&gt;_isLoading&lt;/code&gt; variable to &lt;code&gt;false&lt;/code&gt;. Finally, it returns the &lt;code&gt;User&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;listVendorDocument()&lt;/code&gt; method lists the vendor documents from the Appwrite database and maps the document response to the &lt;code&gt;Vendor&lt;/code&gt; model class. It sets the &lt;code&gt;_vendorItems&lt;/code&gt; instance variable to the mapped vendor documents and the &lt;code&gt;_isLoading&lt;/code&gt; variable to &lt;code&gt;false&lt;/code&gt;. The &lt;code&gt;listOrderDocument()&lt;/code&gt; method also lists the order documents from the Appwrite database and maps the document response to the &lt;code&gt;Order&lt;/code&gt; model class. It sets the &lt;code&gt;_orderItems&lt;/code&gt; instance variable to the mapped order documents.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createOrderDocument&lt;/code&gt; method creates a new order document using the &lt;code&gt;createDocument&lt;/code&gt; method from Appwrite’s database API and notifies listeners of any changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateOrderDocument&lt;/code&gt; method updates an order document's delivery status and delivery time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cancelorder&lt;/code&gt; method cancels an order document by updating its delivery and order information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_subscribe&lt;/code&gt; method subscribes to a real-time update stream of order documents and updates the corresponding order item's order status when an update event occurs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;UI (User interface)&lt;/strong&gt;&lt;br&gt;
The pages folder consists of the entirety of the user interface. The user interface is a single-page interface consisting of a split view with which, when you click the navigation, it redirects to the view linked to the click event. &lt;/p&gt;

&lt;p&gt;The first view (&lt;strong&gt;view_one.dart&lt;/strong&gt;) consists of a row of scrollable containers. These containers will list all the items in the &lt;code&gt;vendor&lt;/code&gt; collection and their corresponding relationship with &lt;code&gt;foodtypes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you click on any of the items, you will get an &lt;code&gt;alertdialog&lt;/code&gt; that shows the items of the &lt;code&gt;foodtype&lt;/code&gt; associated with the particular vendor. This is possible because of the &lt;code&gt;many to many&lt;/code&gt; relation between &lt;code&gt;vendors&lt;/code&gt; and &lt;code&gt;foodtypes&lt;/code&gt;. This relation allows each vendor to have many food types and vice versa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;view_one.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;view_one_modal.dart&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Once an order is created, the order and delivery information are displayed in the order section of the UI in the &lt;code&gt;view_three.dart&lt;/code&gt; file. The Order section of the UI contains a &lt;code&gt;ListTile&lt;/code&gt; widget with an &lt;code&gt;onTap&lt;/code&gt; property that displays a modal showing the order details, a button to cancel an order (by calling the &lt;code&gt;cancelorder&lt;/code&gt; function in the &lt;code&gt;ChangeNotifier&lt;/code&gt; class), and the delivery status. &lt;/p&gt;

&lt;p&gt;Once the order is marked as delivered, a prompt appears in the modal asking the client if they have received their package. If the option is yes, the corresponding document in the delivery collection is updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;view_three.dart&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When you run the application, your result should look like the gifs below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683060682134_ezgif.com-video-to-gif%2B6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683060682134_ezgif.com-video-to-gif%2B6.gif" alt="results"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683302821675_ezgif.com-video-to-gif%2B8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683302821675_ezgif.com-video-to-gif%2B8.gif" alt="results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683303338022_ezgif.com-video-to-gif%2B9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_C9A2C2CC022CFC6BA6F8E7F24A7C0256EB4D70A41022499A4DD2A7808912A3C2_1683303338022_ezgif.com-video-to-gif%2B9.gif" alt="results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Appwrite’s relationship database has shown extreme versatility by providing the option of selecting different relations, which allows for building different scalable applications while being organized. By using the &lt;code&gt;many to many&lt;/code&gt; relation, this tutorial has shown a relationship between different vendors and different food types. Similarly, by using the &lt;code&gt;one to one&lt;/code&gt; relation, we have shown the relationship between one order and one delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/client/databases/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Databases API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/databases-relationships?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Relationship Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/hackmamba/create-a-real-time-parcel-tracking-system-in-flutter-3li3"&gt;Create a real-time parcel tracking system in Flutter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>webdev</category>
      <category>appwrite</category>
    </item>
    <item>
      <title>Getting started with Appwrite Cloud and Flutter</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Mon, 05 Jun 2023 10:52:49 +0000</pubDate>
      <link>https://dev.to/hackmamba/getting-started-with-appwrite-cloud-and-flutter-ao1</link>
      <guid>https://dev.to/hackmamba/getting-started-with-appwrite-cloud-and-flutter-ao1</guid>
      <description>&lt;p&gt;Isn’t it nice to have all the traditional backend features on the web? Appwrite cloud alleviates the need to manage a server. &lt;a href="https://appwrite.io/cloud?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite cloud&lt;/a&gt; is a backend as a service (BaaS) with all the necessary APIs to build your modern application. These APIs assist in building client and server-side applications. A use case of Appwrite is the Database API, which assists in implementing CRUD (create, read, update, delete) features in your application.&lt;/p&gt;

&lt;p&gt;This article will show you how to use an input element to create, store, view and delete text in Flutter using &lt;a href="https://appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow along with this tutorial, the following are required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/" rel="noopener noreferrer"&gt;Xcode&lt;/a&gt; (with developer account for Mac users)&lt;/li&gt;
&lt;li&gt;iOS Simulator, Android Studio, or Chrome web browser to run the application&lt;/li&gt;
&lt;li&gt;Appwrite &lt;a href="https://appwrite.io/cloud?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;cloud&lt;/a&gt; access. It is currently in beta testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating an Appwrite project
&lt;/h2&gt;

&lt;p&gt;You can apply to the &lt;a href="https://cloud.appwrite.io/login?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite cloud&lt;/a&gt; to access the private beta. Once you access Appwrite’s cloud private beta, create a project and fill in the &lt;strong&gt;project's name and id;&lt;/strong&gt; otherwise, &lt;a href="https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9"&gt;use Appwrite locally with Docke&lt;/a&gt;r or &lt;a href="https://marketplace.digitalocean.com/apps/appwrite" rel="noopener noreferrer"&gt;DigitalOcean droplet.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcynje5138vjtj1zy4w84.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcynje5138vjtj1zy4w84.png" alt="Create Project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you will need a database collection to perform CRUD operations. Head to Databases, select &lt;code&gt;Create Database&lt;/code&gt;, and fill in the database &lt;code&gt;name and ID&lt;/code&gt;. After, create a new collection by selecting &lt;code&gt;Create collection&lt;/code&gt; and filling in the subsequent &lt;code&gt;name and ID&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990392_2023-06-03%2B11_39_14-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990392_2023-06-03%2B11_39_14-.png" alt="Databases"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990491_2023-06-03%2B11_37_24-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990491_2023-06-03%2B11_37_24-.png" alt="Create databases"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990580_2023-06-03%2B11_37_55-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990580_2023-06-03%2B11_37_55-.png" alt="Create collections"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is necessary to have parameters to hold data within your collection. Thus, head to the attributes section within the collection created earlier and add the attributes in the following table to the collection:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute key&lt;/th&gt;
&lt;th&gt;Attribute type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;title&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;subtitle&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Finally, head to the collection settings section and set the collection and document level permission to &lt;code&gt;role:any&lt;/code&gt; and check all the CRUD permissions. These permissions allow anyone to create, read, update, and delete documents from the collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183553_2023-06-03%2B11_45_34-Window.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183553_2023-06-03%2B11_45_34-Window.png" alt="Update permission 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183614_2023-06-03%2B11_44_55-Window.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183614_2023-06-03%2B11_44_55-Window.png" alt="Update permission 2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Cloning the UI template
&lt;/h2&gt;

&lt;p&gt;This section uses a UI template containing user registration and login code. Let’s clone the &lt;a href="https://github.com/muyiwexy/getting_started_with_cloud" rel="noopener noreferrer"&gt;repository&lt;/a&gt; specified in the prerequisites. Check out the official GitHub &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository" rel="noopener noreferrer"&gt;docs&lt;/a&gt; to learn more about cloning a repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067276_Screenshot%2B295.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067276_Screenshot%2B295.png" alt="GitHub clone 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067360_Screenshot%2B296.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067360_Screenshot%2B296.png" alt="GitHub clone 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After cloning the UI to your local storage, open it in your preferred code editor and run the command below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This command obtains all the dependencies listed in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file in the current working directory and their transitive dependencies. Next, run the command &lt;code&gt;flutter run&lt;/code&gt;, and your application should look like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685719912564_2023-06-02%2B16_30_41-Window.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685719912564_2023-06-02%2B16_30_41-Window.png" alt="clone result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lib&lt;/code&gt; directory tree should look like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

    &lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;app_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
    &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;documentmodel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
    &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;add_item_modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;edit_item_modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
    &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;
    &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Explaining the UI and functionalities
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Functionalities&lt;/strong&gt;&lt;br&gt;
Before beginning, create a file &lt;code&gt;app_constants.dart&lt;/code&gt; to store important constants from Appwrite. Update the &lt;code&gt;app_constants.dart&lt;/code&gt; with the code below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
class Appconstants {
  static const String projectid = "&amp;lt;projectID&amp;gt;";
  static const String endpoint = "&amp;lt;cloud endpoint&amp;gt;";
  static const String dbID = "&amp;lt;database ID&amp;gt;";
  static const String collectionID = "&amp;lt;collection ID&amp;gt;";
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The project utilizes the Provider package for its state management purposes. Thus, the &lt;code&gt;app_provider.dart&lt;/code&gt; file defines a class named &lt;code&gt;AppProvider&lt;/code&gt; that is implementing &lt;code&gt;ChangeNotifier&lt;/code&gt;. The &lt;code&gt;AppProvider&lt;/code&gt; class contains various methods for creating, listing, updating, and removing documents in a database using the &lt;code&gt;Appwrite&lt;/code&gt; package.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the code above, the &lt;code&gt;AppProvider&lt;/code&gt; class implements the &lt;code&gt;ChangeNotifier&lt;/code&gt; class to handle changes in your application’s state. The &lt;code&gt;Client&lt;/code&gt; class instance, named &lt;code&gt;client&lt;/code&gt;, is tasked with communicating with the Appwrite API.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Account&lt;/code&gt; and &lt;code&gt;Databases&lt;/code&gt; instances communicate with the account and database API. This allows you to create a user account on the client side and perform the CRUD operations.&lt;/p&gt;

&lt;p&gt;The code above uses the &lt;code&gt;initialize&lt;/code&gt; method to set up the &lt;code&gt;client&lt;/code&gt; instance by setting the endpoint and project and creating an anonymous session for the user.&lt;/p&gt;

&lt;p&gt;To utilize the CRUD operations in Appwrite, here is a summary of the document-based methods in the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createDocument&lt;/code&gt; method takes in &lt;code&gt;newTitle&lt;/code&gt;, &lt;code&gt;newSubtitle&lt;/code&gt;, and &lt;code&gt;context&lt;/code&gt; parameters to create a new document in the specified database and collection. It then adds the new document to the list of documents and closes the add document screen.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;listDocument&lt;/code&gt; method lists all the documents in the specified database and collection. It maps the returned list of documents to a list of &lt;code&gt;ListItem&lt;/code&gt; objects and sets the &lt;code&gt;_listItem&lt;/code&gt; variable to this list. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use a model class to map the JSON when getting a list of documents from Appwrite. Thus, add the code below in &lt;code&gt;documentmodel.dart&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
class UserFields {
  static const String id = "\$id";
  static const String title = "title";
  static const String subtitle = "subtitle";
}
class ListItem {
  String? id;
  String? title;
  String? subtitle;
  ListItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
  ListItem.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) {
    id = json[UserFields.id];
    title = json[UserFields.title];
    subtitle = json[UserFields.subtitle];
  }
  Map&amp;lt;String, dynamic&amp;gt; toJson() {
    final Map&amp;lt;String, dynamic&amp;gt; data = &amp;lt;String, dynamic&amp;gt;{};
    data[UserFields.id] = id;
    data[UserFields.title] = title;
    data[UserFields.subtitle] = subtitle;
    return data;
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;updateDocument&lt;/code&gt; method takes in &lt;code&gt;documentId&lt;/code&gt;, &lt;code&gt;updateTitle&lt;/code&gt;, and &lt;code&gt;updateSubtitle&lt;/code&gt; parameters to update the specified document in the database with the new title and subtitle.&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;removeDocument&lt;/code&gt; method takes in &lt;code&gt;documentId&lt;/code&gt; and &lt;code&gt;index&lt;/code&gt; parameters to delete the specified document from the database and remove it from the list of documents. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, the &lt;code&gt;AppProvider&lt;/code&gt; class provides a way to manage documents in an Appwrite database in a Flutter application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI (User interface)&lt;/strong&gt;&lt;br&gt;
The pages folder consists of the entirety of the user interface. The user interface consists of a centered container whose primary action is to display a list of created items. The Container has an &lt;code&gt;ElevatedButton&lt;/code&gt; widget with an &lt;code&gt;onPressed&lt;/code&gt; action displaying a modal. This displayed modal consists of a formfield (input and button) that takes values to create an item.&lt;/p&gt;

&lt;p&gt;To perform an update action, wrap the list in an &lt;code&gt;Inkwell&lt;/code&gt; widget and attach an &lt;code&gt;onTap&lt;/code&gt; property that shows an editable modal that updates the list and the document on Appwrite.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
//Home.dart 

Widget appContainer(BuildContext context, state) {
  return Container(
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
      margin: const EdgeInsets.only(left: 50, right: 50, top: 50),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25.0),
        color: const Color.fromARGB(238, 238, 232, 198),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: ElevatedButton.icon(
              onPressed: () {
                // Handle the tap event by displaying a dialog box where the user can edit the data
                showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    // Return the dialog widget
                    return const AddItemDialog();
                  },
                );
              },
              icon: const Icon(
                Icons.add,
                size: 24.0,
              ),
              label: const Text("Add Item"),
            ),
          ),
          items(state)
        ],
      ));
}
Widget items(state) {
  return Expanded(
      child: Container(
          child: state.listItem.isEmpty
              ? const Center(
                  child: Text(
                    "No items found",
                    style: TextStyle(fontWeight: FontWeight.w800),
                  ),
                )
              : listContainer(state)));
}
Widget listContainer(state) {
  return ListView.builder(
    itemCount: state.listItem.length,
    itemBuilder: (BuildContext context, int index) {
      return InkWell(
        onTap: () {
          // Handle the tap event by displaying a dialog box where the user can edit the data
          showDialog(
            context: context,
            builder: (BuildContext context) {
              // Return the dialog widget
              return EditListItemDialog(
                item: state.listItem[index],
                onSave: (ListItem editedItem) {
                  // Update the item in the list with the edited data
                  state.listItem[index] = editedItem;
                  // Rebuild the UI to reflect the updated data
                  setState(() {});
                },
              );
            },
          );
        },
        child: ListTile(
          title: Text(state.listItem[index].title),
          subtitle: Text(state.listItem[index].subtitle),
          trailing: IconButton(
            icon: const Icon(Icons.delete),
            onPressed: () =&amp;gt;
                state.removeReminder(state.listItem[index].id, index),
          ),
        ),
      );
    },
  );
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Add item AlertDialog&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Edit/Update item AlertDialog&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When you run the application, your result should look like the GIF below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682461851671_ezgif.com-video-to-gif%2B5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropboxusercontent.com%2Fs_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682461851671_ezgif.com-video-to-gif%2B5.gif" alt="result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Though still in beta testing, &lt;a href="https://appwrite.io/cloud?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Cloud&lt;/a&gt; is a game-changer, enabling the creation of backend functionalities swiftly and easily while providing the same benefits as using Appwrite locally. This tutorial has shown how to create CRUD features using the Appwrite cloud and Flutter. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.appwrite.io/login?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/client/databases?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog" rel="noopener noreferrer"&gt;Appwrite Databases API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>appwrite</category>
      <category>webdev</category>
      <category>flutter</category>
    </item>
    <item>
      <title>How to email PDF results with Appwrite cloud, Mailgun and Flutter</title>
      <dc:creator>Femi-ige Muyiwa</dc:creator>
      <pubDate>Wed, 26 Apr 2023 14:29:38 +0000</pubDate>
      <link>https://dev.to/hackmamba/how-to-email-pdf-results-with-appwrite-cloud-mailgun-and-flutter-2o50</link>
      <guid>https://dev.to/hackmamba/how-to-email-pdf-results-with-appwrite-cloud-mailgun-and-flutter-2o50</guid>
      <description>&lt;p&gt;The &lt;strong&gt;cloud:&lt;/strong&gt; a beautiful firmament containing "a visible mass of condensed water vapor floating in the atmosphere, typically high above the general level of the ground." Well, that’s what the Oxford Dictionary said, but the cloud is also a beautiful thing for developers. The cloud is a place of infinite possibilities and boundless opportunities, containing a global network of servers, all with a unique function.&lt;/p&gt;

&lt;p&gt;That brings us to Appwrite. Isn't it great to have all the backend capabilities pushed to the web? With the Appwrite cloud, one can access all the standard backend features without installing anything. This tutorial demonstrates how to create and deploy an Appwrite function to email PDF results with Mailgun and Flutter.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What we are going to cover:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;How to create an Appwrite function&lt;/li&gt;
&lt;li&gt;How to deploy the function to the cloud and locally (Appwrite cloud is still in private beta)&lt;/li&gt;
&lt;li&gt;How to execute the function from the client side using the client SDK&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To folllow along with this tutorial, the following are required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt; (with developer account for Mac users).&lt;/li&gt;
&lt;li&gt;iOS Simulator, Android Studio, or Chrome web browser to run the application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://appwrite.io/docs/command-line?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite CLI&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;Appwrite &lt;a href="https://appwrite.io/cloud?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;cloud&lt;/a&gt; access. It is currently in beta testing.&lt;/li&gt;
&lt;li&gt;Mailgun account access. &lt;a href="https://signup.mailgun.com/new/signup?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Here&lt;/a&gt; is a link to sign up.&lt;/li&gt;
&lt;li&gt;An Appwrite instance running on either Docker, &lt;a href="https://marketplace.digitalocean.com/apps/appwrite"&gt;DigitalOcean droplet&lt;/a&gt;, or &lt;a href="https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod"&gt;Gitpod&lt;/a&gt;. You’ll need this because we will also show how to deploy the function locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Account and project setup
&lt;/h2&gt;

&lt;p&gt;In this section, we’ll cover how to set up the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mailgun account&lt;/li&gt;
&lt;li&gt;Appwrite cloud account&lt;/li&gt;
&lt;li&gt;Appwrite project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Setting up a Mailgun account&lt;/strong&gt;&lt;br&gt;
To sign up for Mailgun, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by &lt;a href="https://signup.mailgun.com/new/signup?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;signing&lt;/a&gt; up for a new account&lt;/li&gt;
&lt;li&gt;Fill out the signup form (name, email address, password) and add the credit card information required&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;Create Account&lt;/code&gt; button to submit the form&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check your email inbox for a confirmation message from Mailgun&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rZveDgAt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679344138324_Screenshot%2B278.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rZveDgAt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679344138324_Screenshot%2B278.png" alt="Mailgun signup" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the instructions in the email to verify the account and complete the signup process.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After completing the signing up and verification processes, we must add and verify our domain to send emails. Here are some places to purchase a domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sso.godaddy.com/v1/login?realm=idp&amp;amp;app=www&amp;amp;path=%2Fen-uk"&gt;Godaddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hostinger.com/"&gt;Hostinger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.namecheap.com/"&gt;nameCheap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, follow the steps below to verify the DNS settings.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After adding the domain or subdomain, open your DNS provider and add the &lt;strong&gt;two TXT DNS records&lt;/strong&gt; provided.&lt;/li&gt;
&lt;li&gt;Next, add the &lt;strong&gt;CNAME&lt;/strong&gt; record to allow Mailgun to track &lt;strong&gt;clicks&lt;/strong&gt; and &lt;strong&gt;opens&lt;/strong&gt;&lt;strong&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Finally,  add the MX records.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once we’ve added the records, our domain will be verified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting up an Appwrite cloud account&lt;/strong&gt;&lt;br&gt;
To sign up for Appwrite, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After registering for the Appwrite cloud beta, you will receive an invite via email.&lt;/li&gt;
&lt;li&gt;Click on the invite link and follow the registration process. That’s it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Setting up the Appwrite project&lt;/strong&gt;&lt;br&gt;
After creating a cloud account, we'll create a platform and an Appwrite project. Let's start by doing the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This process is the same both locally and on the cloud&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;For the Appwrite cloud, you’ll be redirected to the &lt;code&gt;Create project&lt;/code&gt; page after successful sign-in, but locally, we will need to load up the Appwrite console. Thus, open your browser and enter the &lt;code&gt;IP address or hostname&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, choose the &lt;code&gt;Create Project&lt;/code&gt; option and fill in the &lt;code&gt;name and ID&lt;/code&gt; (ID can be automatically generated).&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1FWXS4S_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133088225_Screenshot%2B262.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1FWXS4S_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133088225_Screenshot%2B262.png" alt="Create database" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, we will create a collection to hold the URL string to an online PDF file. Thus, we will create one string attribute called &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4c0wKYNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133157888_Screenshot%2B263.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4c0wKYNy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133157888_Screenshot%2B263.png" alt="Create collection" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;url&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/working-examples/pdf-table/table.pdf"&gt;https://www.w3.org/WAI/WCAG21/working-examples/pdf-table/table.pdf&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Finally, set the collection-level &lt;code&gt;CRUD&lt;/code&gt; permission for both collections to &lt;code&gt;Any&lt;/code&gt; and select all the options.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H1sZslLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133182874_Screenshot%2B264.png" alt="Set crud permission" width="800" height="379"&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2hbI2Y4A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675133218819_Screenshot%2B265.png" alt="Set crud permission 2" width="800" height="382"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Creating an Appwrite project
&lt;/h2&gt;

&lt;p&gt;Next, we’ll create two projects to achieve our desired result. For the first project, we will create an Appwrite function using the Appwrite CLI (command line interface). The second project will be a Flutter project to communicate with the function created earlier after deployment.&lt;/p&gt;

&lt;p&gt;Thus, run the command below to create two directories for the projects, respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;mailgun_function&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="nx"&gt;mailgun_flutter_app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Project&lt;/strong&gt; &lt;strong&gt;o&lt;/strong&gt;&lt;strong&gt;ne (Creating a dart Appwrite function)&lt;/strong&gt;&lt;br&gt;
We will start by enabling the Dart runtime in Appwrite, as it is not naturally included. Head to the default Appwrite directory (when installing locally) and make some edits to the &lt;code&gt;.env&lt;/code&gt; file. Add &lt;code&gt;dart 2-17&lt;/code&gt; to the &lt;code&gt;_APP_FUNCTIONS_RUNTIMES&lt;/code&gt; and &lt;code&gt;_APP_FUNCTIONS_ENVS&lt;/code&gt; variables like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;_APP_FUNCTIONS_RUNTIMES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;16.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.17&lt;/span&gt;
&lt;span class="nx"&gt;_APP_FUNCTIONS_ENVS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;16.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;7.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;ruby&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;dart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.17&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PEjHhf0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679334380585_Screenshot%2B281.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PEjHhf0J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679334380585_Screenshot%2B281.png" alt="Adding dart SDK" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After making the changes, we will run the command below from the default Appwrite directory in our terminal:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;docker&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="nx"&gt;up&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;force&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;recreate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note:  Make sure Docker is running before inputing the command above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we will head to the &lt;code&gt;mailgun_function&lt;/code&gt; folder and log into the Appwrite server using its CLI.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You will receive a prompt to add the email and password you used when registering the local instance. Next, create a new project or specify an existing one. We can do that using the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We will then follow the prompt on how to set the project up.&lt;/p&gt;

&lt;p&gt;Next, we must create an Appwrite function. Therefore, we will do that by running the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Similarly to the previous commands, you will receive a prompt directing you on how to set this up. Once done setting the function up, the command creates a starter project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--557D7E25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679335502671_Screenshot%2B282.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--557D7E25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679335502671_Screenshot%2B282.png" alt="Function folder" width="173" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, head to the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and add the &lt;code&gt;http&lt;/code&gt; package.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.13&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OXFAe4bY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679337703317_Screenshot%2B284.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OXFAe4bY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679337703317_Screenshot%2B284.png" alt="Depedencies" width="463" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;main.dart&lt;/code&gt; file, replace the existing code with the one below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The snippet above does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Imports the required dependencies&lt;/li&gt;
&lt;li&gt;Requests custom payload data when executing the function&lt;/li&gt;
&lt;li&gt;Passes the payload using &lt;code&gt;Uri.parse()&lt;/code&gt;, converts it back to a file, and stores it in temporary storage&lt;/li&gt;
&lt;li&gt;Configures &lt;code&gt;http&lt;/code&gt; mail client by specifying the &lt;strong&gt;API Key&lt;/strong&gt;, and parses the domain URL, to emails, from emails, email content, and email subject&lt;/li&gt;
&lt;li&gt;Sends the email using the configured client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deploy the function&lt;/strong&gt;&lt;br&gt;
For this tutorial, we will show how to deploy the functions both locally and on the cloud.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloud&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to create a function on the Appwrite cloud console to deploy on the cloud. Thus, head to the function section, click &lt;code&gt;Create Function&lt;/code&gt;, fill in the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;ID&lt;/code&gt;, and select the preferred &lt;code&gt;runtime&lt;/code&gt; (dart — 2.17). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SFkg4aRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679782621699_Screenshot%2B285.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SFkg4aRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679782621699_Screenshot%2B285.png" alt="Create function" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, select &lt;code&gt;Create Deployment&lt;/code&gt; and head to the manual deployment. In the manual deployment, we will need to add a &lt;code&gt;tar.gz&lt;/code&gt; fileand specify the &lt;code&gt;entrypoint&lt;/code&gt; for our project. So, head to the folder containing the &lt;code&gt;pubspec.lock&lt;/code&gt; file and run the command below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JBB21Wz3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679782708176_Screenshot%2B286.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JBB21Wz3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679782708176_Screenshot%2B286.png" alt="Create deployment" width="800" height="404"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;czf&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gz&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;exclude&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gz&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command will create a &lt;code&gt;tar.gz&lt;/code&gt; file that can be uploaded to Appwrite. So we will head back to the cloud console, specify the entry point as &lt;code&gt;lib/main.dart&lt;/code&gt;, then add the &lt;code&gt;tar.gz&lt;/code&gt; file and click &lt;code&gt;create&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Locally&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can do this by navigating to the folder containing the &lt;code&gt;appwrite.json&lt;/code&gt; file and then running the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;appwrite&lt;/span&gt; &lt;span class="nx"&gt;deploy&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xMrdx9UO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679340096452_appwrite%2Bdeploy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xMrdx9UO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679340096452_appwrite%2Bdeploy.webp" alt="Local deployment" width="676" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Within the function section, head to the settings section and specify &lt;code&gt;Execute Access&lt;/code&gt; to &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Project two (Creating a Flutter&lt;/strong&gt; &lt;strong&gt;application)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Head to the second folder we created earlier and run the following command&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/muyiwexy/Appwrite_Cloud_MailGun.git &amp;amp;&amp;amp; cd Appwrite_Cloud_MailGun&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This command will clone a flutter template within the current directory and change it to the &lt;code&gt;Appwrite_Cloud_MailGun&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;The template above contains the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;main.dart&lt;/code&gt; file, which contains:

&lt;ul&gt;
&lt;li&gt;A button widget to execute the function on the client side&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;snackbar&lt;/code&gt; to indicate success or failure&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;utils.dart&lt;/code&gt; file, which contains a &lt;code&gt;json&lt;/code&gt; serialize to map the &lt;code&gt;JSON&lt;/code&gt; object received from the database to a model class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we must install and connect our Flutter application to Appwrite.&lt;/p&gt;

&lt;p&gt;First, add &lt;code&gt;Appwrite&lt;/code&gt; to the dependencies section of the &lt;code&gt;pubspec.yaml&lt;/code&gt; file, like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rAz1pKSo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_041BDED8DAB440A4B6CCF96EB23FFFC68E40117CE3B40D930FE7EEC37F7160D4_1675028904318_Screenshot%2B65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rAz1pKSo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_041BDED8DAB440A4B6CCF96EB23FFFC68E40117CE3B40D930FE7EEC37F7160D4_1675028904318_Screenshot%2B65.png" alt="Dependencies" width="628" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, we can use a terminal by typing the command below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;appwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here’s how to connect a Flutter project to Appwrite for Android and iOS devices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;iOS&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, obtain the &lt;code&gt;bundle ID&lt;/code&gt; by navigating to the &lt;code&gt;project.pbxproj&lt;/code&gt; file (&lt;code&gt;ios &amp;gt; Runner.xcodeproj &amp;gt; project.pbxproj&lt;/code&gt;) and searching for the &lt;code&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, head to the &lt;code&gt;Runner.xcworkspace&lt;/code&gt; folder in the application’s iOS folder in the project directory on &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt;. To select the runner target, choose the &lt;strong&gt;Runner&lt;/strong&gt; project in the Xcode project navigator and find the &lt;code&gt;Runner target&lt;/code&gt;. Next, select &lt;code&gt;General and IOS 11.0&lt;/code&gt; in the deployment info section as the target.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_8YrpswT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_8YrpswT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_973FE6248EEDD7529E7A11435E297ADACD4E1B7483EB53A8303EEED9486C6A4E_1677590542497_file.jpeg" alt="iOS" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Android, copy the XML script below and paste it below the activity tag in the &lt;code&gt;Androidmanifest.xml&lt;/code&gt; file (to find this file, head to &lt;code&gt;android &amp;gt; app &amp;gt; src &amp;gt; main&lt;/code&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: change [PROJECT-ID] to the ID you used when creating the Appwrite project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will also need to set up a platform within the Appwrite console. Follow the steps below to do so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Within the Appwrite console, select &lt;code&gt;Create Platform&lt;/code&gt; and choose &lt;code&gt;Flutter&lt;/code&gt; for the platform type.&lt;/li&gt;
&lt;li&gt;Specify the operating system: in this case, Android.&lt;/li&gt;
&lt;li&gt;Finally, provide the application and package names (found in the app-level &lt;code&gt;build.gradle&lt;/code&gt; file).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--egFDRDsy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261190_Screenshot%2B259.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--egFDRDsy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261190_Screenshot%2B259.png" alt="Create platform" width="800" height="362"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g1F15TcX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261213_Screenshot%2B260.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g1F15TcX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_7604AE644359B8A42B0CA41928E7FA82C1E3181DC0A806189A51D7006C234F5A_1675132261213_Screenshot%2B260.png" alt="Create platform" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running the Flutter project&lt;/strong&gt;&lt;br&gt;
Once we are done with the above, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt; &lt;span class="nx"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command obtains all the dependencies in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file. Next, run the &lt;code&gt;flutter run&lt;/code&gt; command to run the project on any desired platform.&lt;/p&gt;

&lt;p&gt;Here is the result of the code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zltVCOgk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679343517861_ezgif.com-video-to-gif%2B4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zltVCOgk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://paper-attachments.dropboxusercontent.com/s_43DBDC09534E0739E7C8C10CC0F42B993011AB266FDB05C08DF6644BC9354199_1679343517861_ezgif.com-video-to-gif%2B4.gif" alt="Result" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, emailing PDF results with Appwrite Cloud, Mailgun, and Flutter is a straightforward process that can be accomplished with simple steps. By using &lt;a href="https://appwrite.io/cloud?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite Cloud&lt;/a&gt; to generate and retrieve PDF results, Mailgun to send email notifications, and Flutter to handle the user interface and app logic, developers can easily create a robust and efficient system for emailing PDF results to users. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/getting-started-for-flutter?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite Flutter SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/functions?utm_source=hackmamba&amp;amp;utm_medium=hackmamba-blog"&gt;Appwrite Function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>appwrite</category>
      <category>flutter</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
