<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ crud - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ crud - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 28 May 2026 04:42:02 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/crud/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Extend CRUD Operations to Align with Business Workflows ]]>
                </title>
                <description>
                    <![CDATA[ Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/extend-crud-operations-to-align-with-business-workflows/</link>
                <guid isPermaLink="false">68c19bc01159a9ac851f6cb5</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Backend Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Wed, 10 Sep 2025 15:39:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757518255485/8e727e36-d22a-42d9-b1a7-98d3ca5eae35.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate it. We teach it to beginners as the foundation of working with data.</p>
<p>But once you move beyond basic apps, CRUD starts to fall apart.</p>
<p>Real-world systems don’t just “update” or “delete” things. In a loan application system, for example, borrowers “submit” applications, loan officers “approve” or “reject” them, and applications are eventually “archived”. These aren’t generic CRUD operations—they’re <strong>domain-specific actions</strong> that carry meaning.</p>
<p>And that’s the problem: CRUD hides the meaning of our systems behind vague verbs. REST APIs inherit the same issue, mapping HTTP verbs onto CRUD but still failing to express real workflows clearly.</p>
<p>In this article, we’ll explore:</p>
<ul>
<li><p>Why CRUD works fine for simple apps but becomes an anti-pattern at scale</p>
</li>
<li><p>How concepts like <strong>upsert</strong>, <strong>archive</strong>, and <strong>bulk operations</strong> reveal its cracks</p>
</li>
<li><p>Why REST doesn’t solve these issues</p>
</li>
<li><p>How to design APIs around domain actions and workflows instead.</p>
</li>
</ul>
<p>By the end, you’ll see CRUD for what it really is—a teaching tool, not a design philosophy.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-crud">What is CRUD?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p><strong>Create, Read, Update, Delete</strong>—these are the four basic operations we perform on data in a database.</p>
<ul>
<li><p><strong>Create</strong> – adds a new record.</p>
</li>
<li><p><strong>Read</strong> – fetches an existing record (or list of records).</p>
</li>
<li><p><strong>Update</strong> – changes one or more fields in a record.</p>
</li>
<li><p><strong>Delete</strong> – removes a record.</p>
</li>
</ul>
<p>For example, in a typical Node.js + Express app managing users:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a user</span>
app.post(<span class="hljs-string">'/users'</span>, createUser);

<span class="hljs-comment">// Read a user</span>
app.get(<span class="hljs-string">'/users/:id'</span>, getUser);

<span class="hljs-comment">// Update a user</span>
app.put(<span class="hljs-string">'/users/:id'</span>, updateUser);

<span class="hljs-comment">// Delete a user</span>
app.delete(<span class="hljs-string">'/users/:id'</span>, deleteUser);
</code></pre>
<p>This maps directly to the underlying SQL:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (...);
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">SET</span> ... <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
</code></pre>
<p>And that’s CRUD in its purest form—four operations that can describe almost any database interaction.</p>
<h2 id="heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</h2>
<p>Developers quickly realize CRUD isn’t enough, so they invent extensions:</p>
<ul>
<li><p><strong>Upsert</strong>: a mix of “update” and “insert.” If the record exists, update it; if not, create it.</p>
</li>
<li><p><strong>Archive</strong>: instead of deleting a record, we “soft delete” or mark it as inactive so the history stays intact.</p>
</li>
<li><p><strong>Bulk operations</strong>: run create, update, or delete on many records at once for efficiency.</p>
</li>
</ul>
<p>These solve real problems, but they stretch CRUD’s simple model. We now need to distinguish between single and bulk resource actions. And we also need to factor in the technical concerns of upsertions and soft deletions.</p>
<h2 id="heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</h2>
<p>The technical domain itself stretches CRUD substantially, but business domain concerns break it entirely. Take a loan application system:</p>
<ul>
<li><p>A borrower doesn’t “create” and “update” an application—they start, submit, or withdraw it.</p>
</li>
<li><p>A loan officer doesn’t “update” an application—they review, approve, or reject it.</p>
</li>
<li><p>Applications don’t get “deleted”—they’re usually archived so there’s a record for compliance.</p>
</li>
</ul>
<p>If we try to model these as plain CRUD, the meaning gets lost:</p>
<pre><code class="lang-http"><span class="hljs-attribute">PATCH /applications/123 { "status"</span>: "approved" }
</code></pre>
<p>Technically, it works. But what does “update” really mean here? Was the application submitted, rejected, or archived? You can’t tell from the API call.</p>
<p>The core problem: CRUD hides intent behind generic, technical language. Real business processes are expressed as domain-specific actions, not generic updates or deletes.</p>
<h2 id="heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</h2>
<p>CRUD not only obscures intent—it also creates authorization gaps. Using the same loan application example:</p>
<ul>
<li><p>Only loan officers should approve applications.</p>
</li>
<li><p>Borrowers should only edit their own information or withdraw their applications.</p>
</li>
</ul>
<p>If “approve” is just modeled as a generic update, the system can’t distinguish between roles without additional checks. A naive authorization rule like “can this user update?” suddenly lets borrowers perform actions reserved for officers.</p>
<p>This mismatch between technical verbs and business rules can lead to:</p>
<ul>
<li><p>Security issues—unauthorized actions performed by the wrong user.</p>
</li>
<li><p>Audit problems—it’s unclear who did what, and when.</p>
</li>
<li><p>Workflow confusion—state transitions get lost in generic updates.</p>
</li>
</ul>
<p>The solution: treat each domain action as its own API call with explicit authorization rules:</p>
<pre><code class="lang-http"><span class="hljs-attribute">POST /applications/123/approve   # Only accessible to loan officers
POST /applications/123/withdraw  # Only accessible to the borrower</span>
</code></pre>
<p>By modeling actions instead of CRUD operations, intent and permissions are clear, reducing both bugs and security risks.</p>
<h2 id="heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</h2>
<p>Real-world applications follow workflows—sequences of states that a resource moves through. Take our loan application example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757257665063/f26ce4c4-afee-4b03-8ddc-bdb724aa9850.png" alt="Loan Application Workflow Diagram" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here’s what the corresponding API endpoints might look like:</p>
<pre><code class="lang-http"># Borrower actions
<span class="hljs-attribute">POST /applications/123/submit       # Draft → Submitted
POST /applications/123/withdraw     # Draft/Submitted → Closed

# Loan officer actions
POST /applications/123/approve      # Submitted → Approved
POST /applications/123/reject       # Submitted → Rejected

# System/Admin actions
POST /applications/123/close        # Approved/Rejected → Closed

# Side effect</span>: spawning a Loan (after Approved)
<span class="hljs-attribute">POST /loans
{
  "applicationId"</span>: "123",
  "amount": 50000,
  "borrowerId": "456",
  "terms": { ... }
}
</code></pre>
<p>At this point, our API calls are almost entirely outside the CRUD pattern—the only one that resembles a CRUD action is the spawning of a loan, which looks like a “create”. Behind the scenes, we’ll still use <code>INSERT</code>, <code>SELECT</code>, and <code>UPDATE</code> statements in SQL, but at the API level we’re aligning to the actual business workflow. Because of it, we’re able to easily support the following:</p>
<ol>
<li><p><strong>Actions reflect business intent</strong> — each API call maps to a real-world task like submit, approve, or withdraw.</p>
</li>
<li><p><strong>Built-in authorization</strong> — endpoints clearly separate borrower, loan officer, and admin responsibilities.</p>
</li>
<li><p><strong>Auditability and workflow enforcement</strong> — state transitions are explicit and invalid transitions are prevented.</p>
</li>
<li><p><strong>Controlled side effects</strong> — spawning loans, notifications, and downstream processes are handled deliberately.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By moving away from CRUD and modeling domain actions instead, our API aligns with real business workflows, clearly communicates intent, and enforces rules and authorization naturally. State transitions, side effects, and auditing become explicit, reducing errors and security risks. While CRUD still powers the underlying database operations, thinking in terms of actions and workflows ensures that the system behaves the way the business expects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a CRUD Application using React and Convex ]]>
                </title>
                <description>
                    <![CDATA[ CRUD operations are the basis of every application, so it is essential to become proficient in them when learning new technologies. In this tutorial, you’ll learn how to build a CRUD application using React and Convex. We’ll cover these operations by... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-crud-app-react-and-convex/</link>
                <guid isPermaLink="false">671a5f1685689d5790d302c5</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sanjay ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2024 14:52:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729397399755/9c747607-fa82-4caf-9c20-8e64ec82c3f2.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CRUD operations are the basis of every application, so it is essential to become proficient in them when learning new technologies.</p>
<p>In this tutorial, you’ll learn how to build a CRUD application using React and Convex. We’ll cover these operations by building a project called Book Collections. In this project, users will be able to add books and update their status once they complete a book.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-convex">What is Convex?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-project">How to Set Up Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-schema">How to Create the Schema</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-ui">How to Create the UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-crud-functions">How to Create CRUD Functions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-styling">Styling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-convex">What is Convex?</h2>
<p>Convex is the Baas Platform that simplifies backend development. Convex comes with a real-time database, and you do not need to worry about writing server-side logic separately because it provides methods for querying and mutating the database.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>In order to follow this tutorial, you must know the fundamentals of React. I will be using TypeScript in this project, but it is optional, so you can also follow along with JavaScript.</p>
<h2 id="heading-how-to-set-up-your-project">How to Set Up Your Project</h2>
<p>Create a separate folder for the project and name it as you wish – I will name mine <strong>Books.</strong> We’ll set up Convex and React in that folder.</p>
<p>You can create a React app using this command:</p>
<pre><code class="lang-bash">npm create vite@latest my-app -- --template react-ts
</code></pre>
<p>If you want to work with JavaScript, then remove the <code>ts</code> at the end. That is:</p>
<pre><code class="lang-bash">npm create vite@latest my-app -- --template react
</code></pre>
<h3 id="heading-how-to-setup-convex">How to Setup Convex</h3>
<p>We have to install Convex in the same folder. You can do that using this command:</p>
<pre><code class="lang-bash">npm install convex
</code></pre>
<p>Next, run <code>npx convex dev</code>. If you’re doing this for the first time, it should ask you for authentication. Otherwise, it should ask for the project name.</p>
<p>You can visit the <a target="_blank" href="https://www.convex.dev/">Convex dashboard</a> to see the project that you have created.</p>
<p>Now that we have the Convex and React App set up, we need to connect the Convex backend to the React app.</p>
<p>In the <strong>src/main.tsx</strong>, wrap your <code>App</code> component with the <code>ConvexReactClient</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.tsx"</span>;
<span class="hljs-keyword">import</span> { ConvexProvider, ConvexReactClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>

<span class="hljs-keyword">const</span> convex = <span class="hljs-keyword">new</span> ConvexReactClient(<span class="hljs-keyword">import</span>.meta.env.VITE_CONVEX_URL <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>);

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)!).render(
  &lt;ConvexProvider client={convex}&gt;
    &lt;App /&gt;
  &lt;/ConvexProvider&gt;
);
</code></pre>
<p>When you set up Convex, a <code>.env.local</code> was created. You can see your backend URL in that file.</p>
<p>In the line below, we instantiated the React Convex Client with the URL.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> convex = <span class="hljs-keyword">new</span> ConvexReactClient(<span class="hljs-keyword">import</span>.meta.env.VITE_CONVEX_URL <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>);
</code></pre>
<h2 id="heading-how-to-create-the-schema">How to Create the Schema</h2>
<p>In your main project directory, you should see the <strong>convex</strong> directory. We’ll handle the database queries and mutations here.</p>
<p>Create a <strong>schema.ts</strong> file in the <strong>convex</strong> folder:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { defineSchema, defineTable } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/server"</span>;
<span class="hljs-keyword">import</span> { v } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/values"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineSchema({
  books: defineTable({
    title: v.string(),
    author: v.string(),
    isCompleted: v.boolean(),
  }),
});
</code></pre>
<p>You can define a Schema for your document with <code>defineSchema</code> and create a table with <code>defineTable</code>. Convex provides these functions for defining a schema and creating a table.</p>
<p><code>v</code> is the type validator, it is used to provide types for each data we add to the table.</p>
<p>For this project, as it is a book collection application, the structure will have <code>title</code>, <code>author</code>, and <code>isCompleted</code>. You can add more fields.</p>
<p>Now that you have defined your schema, let’s set up the basic UI in React.</p>
<h2 id="heading-how-to-create-the-ui">How to Create the UI</h2>
<p>In the <strong>src</strong> folder, create a folder called <strong>component</strong> and a file <strong>Home.tsx</strong>. Here, you can define the UI.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/home.css"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [author, setAuthor] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"main-container"</span>&gt;
      &lt;h1&gt;Book Collections&lt;/h1&gt;
      &lt;form onSubmit={handleSubmit}&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          name=<span class="hljs-string">"title"</span>
          value={title}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setTitle(e.target.value)}
          placeholder=<span class="hljs-string">"book title"</span>
        /&gt;
        &lt;br /&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          name=<span class="hljs-string">"author"</span>
          value={author}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setAuthor(e.target.value)}
          placeholder=<span class="hljs-string">"book author"</span>
        /&gt;
        &lt;br /&gt;
        &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> /&gt;
      &lt;/form&gt;
      {books ? &lt;Books books={books} /&gt; : <span class="hljs-string">"Loading..."</span>}
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>You can create your component as you wish. I added two input fields <code>title</code>, <code>author</code>, and <code>submit</code> button. This is the basic structure. Now we can create CRUD methods in the backend.</p>
<h2 id="heading-how-to-create-crud-functions">How to Create CRUD Functions</h2>
<p>In the <strong>convex</strong> folder, you can create a separate <strong>queries.ts</strong> file for the CRUD functions.</p>
<h3 id="heading-create-function">Create Function</h3>
<p>In <strong>convex/queries.ts</strong>:</p>
<p>You can define a function <code>createBooks</code>. You can use the <code>mutation</code> function from Convex to create, update, and delete data. Reading the data will come under <code>query</code>.</p>
<p>The <code>mutation</code> function expects these arguments:</p>
<ul>
<li><p><code>agrs</code>: the data we need to store in the database.</p>
</li>
<li><p><code>handler</code>: handles the logic to store date in the database. The <code>handler</code> is an async function, and it has two arguments: <code>ctx</code> and <code>args</code>. Here, <code>ctx</code> is the context object that we’ll use to handle the database operations.</p>
</li>
</ul>
<p>You’ll use the <code>insert</code> method to insert new data. The first parameter in the <code>insert</code> is the table name and the second is the data that needs to be inserted.</p>
<p>Lastly, you can return the data from the database.</p>
<p>Here’s the code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { mutation} <span class="hljs-keyword">from</span> <span class="hljs-string">"./_generated/server"</span>;
<span class="hljs-keyword">import</span> { v } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/values"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createBooks = mutation({
  args: { title: v.string(), author: v.string() },
  handler: <span class="hljs-keyword">async</span> (ctx, args) =&gt; {
    <span class="hljs-keyword">const</span> newBookId = <span class="hljs-keyword">await</span> ctx.db.insert(<span class="hljs-string">"books"</span>, {
      title: args.title,
      author: args.author,
      isCompleted: <span class="hljs-literal">false</span>,
    });
    <span class="hljs-keyword">return</span> newBookId;
  },
});
</code></pre>
<h3 id="heading-read-function">Read Function</h3>
<p>In <strong>convex/queries.ts</strong>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { query } <span class="hljs-keyword">from</span> <span class="hljs-string">"./_generated/server"</span>;
<span class="hljs-keyword">import</span> { v } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/values"</span>;

<span class="hljs-comment">//read</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getBooks = query({
  args: {},
  handler: <span class="hljs-keyword">async</span> (ctx) =&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> ctx.db.query(<span class="hljs-string">"books"</span>).collect();
  },
});
</code></pre>
<p>In this read operation, we used the built-in <code>query</code> function from Convex. Here, <code>args</code> will be empty since we are not getting any data from the user. Similarly, the <code>handler</code> function is async and uses the <code>ctx</code> object to query the database and return the data.</p>
<h3 id="heading-update-function">Update Function</h3>
<p>In <strong>convex/queries.ts</strong>:</p>
<p>Create a <code>updateStatus</code> function. We are only going to update the <code>isCompleted</code> status.</p>
<p>Here, you need to get the document ID and the status from the user. In the <code>args</code>, we’ll define <code>id</code> and the <code>isCompleted</code>, which will come from the user.</p>
<p>In the <code>handler</code>, we’ll use the <code>patch</code> method to update the data. The <code>patch</code> method expects two arguments: the first argument is the <code>id</code> of the document and the second is the updated data.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { mutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"./_generated/server"</span>;
<span class="hljs-keyword">import</span> { v } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/values"</span>;

<span class="hljs-comment">//update</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateStatus = mutation({
  args: { id: v.id(<span class="hljs-string">"books"</span>), isCompleted: v.boolean() },
  handler: <span class="hljs-keyword">async</span> (ctx, args) =&gt; {
    <span class="hljs-keyword">const</span> { id } = args;
    <span class="hljs-keyword">await</span> ctx.db.patch(id, { isCompleted: args.isCompleted });
    <span class="hljs-keyword">return</span> <span class="hljs-string">"updated"</span>
  },
});
</code></pre>
<h3 id="heading-delete-function">Delete Function</h3>
<p>In <strong>convex/queries.ts</strong>:</p>
<p>Create a <code>deleteBooks</code> function and use the <code>mutation</code> function. We’ll need the ID of the document to be deleted. In the <code>args</code>, define an ID. In the <code>handler</code>, use the <code>ctx</code> object <code>delete</code> method, and pass the ID. This will delete the document.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { mutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"./_generated/server"</span>;
<span class="hljs-keyword">import</span> { v } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/values"</span>;

<span class="hljs-comment">//delete</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteBooks = mutation({
  args: { id: v.id(<span class="hljs-string">"books"</span>) },
  handler: <span class="hljs-keyword">async</span> (ctx, args) =&gt; {
    <span class="hljs-keyword">await</span> ctx.db.delete(args.id);
    <span class="hljs-keyword">return</span> <span class="hljs-string">"deleted"</span>;
  },
});
</code></pre>
<p>As of now, you have completed the CRUD functions in the backend. Now we need to make it work in the UI. Let’s jump back to React.</p>
<h3 id="heading-update-the-ui">Update the UI</h3>
<p>You’ve already created some basic UI in the React app, along with some input fields. Let’s update it.</p>
<p>In <strong>src/component/Home.tsx</strong>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useQuery, useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/react"</span>;
<span class="hljs-keyword">import</span> { api } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/api"</span>;
<span class="hljs-keyword">import</span> { Books } <span class="hljs-keyword">from</span> <span class="hljs-string">"./Books"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/home.css"</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [author, setAuthor] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> books = useQuery(api.queries.getBooks);
  <span class="hljs-keyword">const</span> createBooks = useMutation(api.queries.createBooks);

  <span class="hljs-keyword">const</span> handleSubmit = (e: React.FormEvent&lt;HTMLFormElement&gt;): <span class="hljs-function"><span class="hljs-params">void</span> =&gt;</span> {
    e.preventDefault();
    createBooks({ title, author })
      .then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"created"</span>);
        setTitle(<span class="hljs-string">""</span>);
        setAuthor(<span class="hljs-string">""</span>);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  };
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"main-container"</span>&gt;
      &lt;h1&gt;Book Collections&lt;/h1&gt;
      &lt;form onSubmit={handleSubmit}&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          name=<span class="hljs-string">"title"</span>
          value={title}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setTitle(e.target.value)}
          placeholder=<span class="hljs-string">"book title"</span>
        /&gt;
        &lt;br /&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          name=<span class="hljs-string">"author"</span>
          value={author}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setAuthor(e.target.value)}
          placeholder=<span class="hljs-string">"book author"</span>
        /&gt;
        &lt;br /&gt;
        &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> /&gt;
      &lt;/form&gt;
      {books ? &lt;Books books={books} /&gt; : <span class="hljs-string">"Loading..."</span>}
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>We can now use the backend API functions by using <code>api</code> from Convex. As you can see, we called two API functions: you can use <code>useQuery</code> if you’re going to read data and <code>useMutation</code> if you want to change data. Now in this file, we are doing, two operations that are create and read.</p>
<p>We got all the data by using this method:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> books = useQuery(api.queries.getBooks);
</code></pre>
<p>The array of objects will be stored in the books variable.</p>
<p>We got the create function from the backend with this line of code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> createBooks = useMutation(api.queries.createBooks);
</code></pre>
<h3 id="heading-how-to-use-the-create-function-in-the-ui">How to Use the Create Function in the UI</h3>
<p>Let’s use the create function in the UI.</p>
<p>Since input fields are in the <code>form</code> tag, we’ll use the <code>onSubmit</code> attribute to handle the form submission.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//In the Home.tsx</span>

<span class="hljs-keyword">const</span> handleSubmit = (e: React.FormEvent&lt;HTMLFormElement&gt;): <span class="hljs-function"><span class="hljs-params">void</span> =&gt;</span> {
    e.preventDefault();
    createBooks({ title, author })
      .then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"created"</span>);
        setTitle(<span class="hljs-string">""</span>);
        setAuthor(<span class="hljs-string">""</span>);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  };
</code></pre>
<p>When you click submit, it triggers the <code>handleSubmit</code> function.</p>
<p>We used the <code>createBooks</code> to pass the <code>title</code> and <code>author</code> from the state. The endpoint function is async, so we can use the <code>handleSubmit</code> as async or use <code>.then</code>. I used the <code>.then</code> method to handle the asynchronous data.</p>
<p>You can create a separate component to display the data fetched from the database. The returned data is in the <strong>Home.tsx</strong>, so we will pass the data to the <strong>Books.tsx</strong> component as props.</p>
<p>In <strong>Books.tsx</strong>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { book } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types/book.type"</span>;
<span class="hljs-keyword">import</span> { useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/react"</span>;
<span class="hljs-keyword">import</span> { api } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/api"</span>;
<span class="hljs-keyword">import</span> { Id } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/dataModel"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/book.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Books = <span class="hljs-function">(<span class="hljs-params">{ books }: { books: book[] }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [id, setId] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> deleteBooks = useMutation(api.queries.deleteBooks);
  <span class="hljs-keyword">const</span> updateStatus = useMutation(api.queries.updateStatus);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setId(id);
    setUpdate(!update);
  };

  <span class="hljs-keyword">const</span> handleDelete = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    deleteBooks({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt; })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  };

  <span class="hljs-keyword">const</span> handleUpdate = <span class="hljs-function">(<span class="hljs-params">e: React.FormEvent&lt;HTMLFormElement&gt;, id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-keyword">const</span> formdata = <span class="hljs-keyword">new</span> FormData(e.currentTarget);
    <span class="hljs-keyword">const</span> isCompleted: <span class="hljs-built_in">boolean</span> =
      (formdata.get(<span class="hljs-string">"completed"</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>) === <span class="hljs-string">"true"</span>;
    updateStatus({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt;, isCompleted })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
    setUpdate(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {books.map(<span class="hljs-function">(<span class="hljs-params">data: book, index: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> (
          &lt;div
            key={data._id}
            className={<span class="hljs-string">`book-container <span class="hljs-subst">${data.isCompleted ? <span class="hljs-string">"completed"</span> : <span class="hljs-string">"not-completed"</span>}</span>`</span>}
          &gt;
            &lt;h3&gt;Book no: {index + <span class="hljs-number">1</span>}&lt;/h3&gt;
            &lt;p&gt;Book title: {data.title}&lt;/p&gt;
            &lt;p&gt;Book Author: {data.author}&lt;/p&gt;
            &lt;p&gt;
              Completed Status:{<span class="hljs-string">" "</span>}
              {data.isCompleted ? <span class="hljs-string">"Completed"</span> : <span class="hljs-string">"Not Completed"</span>}
            &lt;/p&gt;
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleClick(data._id)}&gt;Update&lt;/button&gt;
            {id === data._id &amp;&amp; update &amp;&amp; (
              &lt;&gt;
                &lt;form onSubmit={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleUpdate(e, data._id)}&gt;
                  &lt;select name=<span class="hljs-string">"completed"</span>&gt;
                    &lt;option value=<span class="hljs-string">"true"</span>&gt;Completed&lt;/option&gt;
                    &lt;option value=<span class="hljs-string">"false"</span>&gt;Not Completed&lt;/option&gt;
                  &lt;/select&gt;
                  &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> /&gt;
                &lt;/form&gt;
              &lt;/&gt;
            )}
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleDelete(data._id)}&gt;<span class="hljs-keyword">delete</span>&lt;/button&gt;
          &lt;/div&gt;
        );
      })}
    &lt;/div&gt;
  );
};
</code></pre>
<p>In the <strong>Books.jsx</strong> component, you can display data from the database and handle the functionality for updating and deleting records.</p>
<p>Let’s walk through each of these features step by step.</p>
<h3 id="heading-how-to-display-the-data">How to Display the Data</h3>
<p>You can get the data passed as a prop in the <code>Home.tsx</code> component. If you are using TypeScript, I have defined a type for the object that is returned from the query. You can ignore this if you are using JavaScript.</p>
<p>Create `<strong>books.types.ts</strong>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> book = {
    _id: <span class="hljs-built_in">string</span>,
    title: <span class="hljs-built_in">string</span>,
    author: <span class="hljs-built_in">string</span>,
    isCompleted: <span class="hljs-built_in">boolean</span>
}
</code></pre>
<p>You can use the <code>map</code> function to display the data.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { book } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types/book.type"</span>;
<span class="hljs-keyword">import</span> { useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/react"</span>;
<span class="hljs-keyword">import</span> { api } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/api"</span>;
<span class="hljs-keyword">import</span> { Id } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/dataModel"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/book.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Books = <span class="hljs-function">(<span class="hljs-params">{ books }: { books: book[] }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {books.map(<span class="hljs-function">(<span class="hljs-params">data: book, index: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> (
          &lt;div
            key={data._id}
            className={<span class="hljs-string">`book-container <span class="hljs-subst">${data.isCompleted ? <span class="hljs-string">"completed"</span> : <span class="hljs-string">"not-completed"</span>}</span>`</span>}
          &gt;
            &lt;h3&gt;Book no: {index + <span class="hljs-number">1</span>}&lt;/h3&gt;
            &lt;p&gt;Book title: {data.title}&lt;/p&gt;
            &lt;p&gt;Book Author: {data.author}&lt;/p&gt;
            &lt;p&gt;
              Completed Status:{<span class="hljs-string">" "</span>}
              {data.isCompleted ? <span class="hljs-string">"Completed"</span> : <span class="hljs-string">"Not Completed"</span>}
            &lt;/p&gt;
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleClick(data._id)}&gt;Update&lt;/button&gt;
            {id === data._id &amp;&amp; update &amp;&amp; (
              &lt;&gt;
                &lt;form onSubmit={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleUpdate(e, data._id)}&gt;
                  &lt;select name=<span class="hljs-string">"completed"</span>&gt;
                    &lt;option value=<span class="hljs-string">"true"</span>&gt;Completed&lt;/option&gt;
                    &lt;option value=<span class="hljs-string">"false"</span>&gt;Not Completed&lt;/option&gt;
                  &lt;/select&gt;
                  &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> /&gt;
                &lt;/form&gt;
              &lt;/&gt;
            )}
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleDelete(data._id)}&gt;<span class="hljs-keyword">delete</span>&lt;/button&gt;
          &lt;/div&gt;
        );
      })}
    &lt;/div&gt;
  );
};
</code></pre>
<p>This is the basic structure. We displayed the title, author, and status, along with an update and delete button.</p>
<p>Now, let’s add the functionalities.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { book } <span class="hljs-keyword">from</span> <span class="hljs-string">"../types/book.type"</span>;
<span class="hljs-keyword">import</span> { useMutation } <span class="hljs-keyword">from</span> <span class="hljs-string">"convex/react"</span>;
<span class="hljs-keyword">import</span> { api } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/api"</span>;
<span class="hljs-keyword">import</span> { Id } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../convex/_generated/dataModel"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"../styles/book.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Books = <span class="hljs-function">(<span class="hljs-params">{ books }: { books: book[] }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [update, setUpdate] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [id, setId] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> deleteBooks = useMutation(api.queries.deleteBooks);
  <span class="hljs-keyword">const</span> updateStatus = useMutation(api.queries.updateStatus);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setId(id);
    setUpdate(!update);
  };

  <span class="hljs-keyword">const</span> handleDelete = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    deleteBooks({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt; })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  };

  <span class="hljs-keyword">const</span> handleUpdate = <span class="hljs-function">(<span class="hljs-params">e: React.FormEvent&lt;HTMLFormElement&gt;, id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-keyword">const</span> formdata = <span class="hljs-keyword">new</span> FormData(e.currentTarget);
    <span class="hljs-keyword">const</span> isCompleted: <span class="hljs-built_in">boolean</span> =
      (formdata.get(<span class="hljs-string">"completed"</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>) === <span class="hljs-string">"true"</span>;
    updateStatus({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt;, isCompleted })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
    setUpdate(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {books.map(<span class="hljs-function">(<span class="hljs-params">data: book, index: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> (
          &lt;div
            key={data._id}
            className={<span class="hljs-string">`book-container <span class="hljs-subst">${data.isCompleted ? <span class="hljs-string">"completed"</span> : <span class="hljs-string">"not-completed"</span>}</span>`</span>}
          &gt;
            &lt;h3&gt;Book no: {index + <span class="hljs-number">1</span>}&lt;/h3&gt;
            &lt;p&gt;Book title: {data.title}&lt;/p&gt;
            &lt;p&gt;Book Author: {data.author}&lt;/p&gt;
            &lt;p&gt;
              Completed Status:{<span class="hljs-string">" "</span>}
              {data.isCompleted ? <span class="hljs-string">"Completed"</span> : <span class="hljs-string">"Not Completed"</span>}
            &lt;/p&gt;
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleClick(data._id)}&gt;Update&lt;/button&gt;
            {id === data._id &amp;&amp; update &amp;&amp; (
              &lt;&gt;
                &lt;form onSubmit={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleUpdate(e, data._id)}&gt;
                  &lt;select name=<span class="hljs-string">"completed"</span>&gt;
                    &lt;option value=<span class="hljs-string">"true"</span>&gt;Completed&lt;/option&gt;
                    &lt;option value=<span class="hljs-string">"false"</span>&gt;Not Completed&lt;/option&gt;
                  &lt;/select&gt;
                  &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> /&gt;
                &lt;/form&gt;
              &lt;/&gt;
            )}
            &lt;button onClick={<span class="hljs-function">() =&gt;</span> handleDelete(data._id)}&gt;<span class="hljs-keyword">delete</span>&lt;/button&gt;
          &lt;/div&gt;
        );
      })}
    &lt;/div&gt;
  );
};
</code></pre>
<p>This is the entire component code. Let me explain what we did.</p>
<p>First, we need to toggle the update, so we defined the <code>handleClick</code> function, and passed a document ID to it.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//handleClick</span>
 <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setId(id);
    setUpdate(!update);
  };
</code></pre>
<p>In the <code>handleClick</code> you can update the ID state and toggle the update state so that it will toggle the update input when clicked, and on another click, it will close.</p>
<p>Next, we have <code>handleUpdate</code>. We need the document ID to update the data, so we passed the event object as well as the document ID. To get the input, we can use <code>FormData</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> updateStatus = useMutation(api.queries.updateStatus);

<span class="hljs-keyword">const</span> handleUpdate = <span class="hljs-function">(<span class="hljs-params">e: React.FormEvent&lt;HTMLFormElement&gt;, id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-keyword">const</span> formdata = <span class="hljs-keyword">new</span> FormData(e.currentTarget);
    <span class="hljs-keyword">const</span> isCompleted: <span class="hljs-built_in">boolean</span> =
      (formdata.get(<span class="hljs-string">"completed"</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>) === <span class="hljs-string">"true"</span>;
    updateStatus({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt;, isCompleted })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
    setUpdate(<span class="hljs-literal">false</span>);
  };
</code></pre>
<p>We need to use the <code>useMutation</code> to get the <code>updateStatus</code> function. Pass the ID and the completed status to the function, and handle the asynchronous part using <code>.then</code></p>
<p>For the delete function, the document ID is enough. Just like the previous one, call the delete function using the <code>useMutation</code> and pass the ID to it.</p>
<p>Then pass the document ID and handle the promise.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> deleteBooks = useMutation(api.queries.deleteBooks);

<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    deleteBooks({ id: id <span class="hljs-keyword">as</span> Id&lt;<span class="hljs-string">"books"</span>&gt; })
      .then(<span class="hljs-function">(<span class="hljs-params">mess</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(mess))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
 };
</code></pre>
<h2 id="heading-styling">Styling</h2>
<p>Finally, what’s left is to add some styling. I added some basic styling. If the book has not been completed, it will be in red, and if the book has been completed, it will be in green.</p>
<p>Here’s the screenshot:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729428111374/1d1a69ef-5d35-4410-91f4-d8cf4817991d.png" alt="final output" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This is it guys!!</p>
<p>You can check my repository for the full code: <a target="_blank" href="https://github.com/sanjayr-12/convex-crud">convex-curd</a></p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we implemented the CRUD (Create, Read, Update, and Delete) operations by building a book collections app. We begin by setting up Convex and React, and writing CRUD logic.</p>
<p>This tutorial covered both the frontend and the backend, demonstrating how to build a serverless application.</p>
<p>You can find the full code here: <a target="_blank" href="https://github.com/sanjayr-12/convex-crud">convex-curd</a></p>
<p>If there are any mistakes or any doubt contact me on <a target="_blank" href="https://www.linkedin.com/in/sanjay-r-ab6064294/">LinkedIn</a>, <a target="_blank" href="https://www.instagram.com/_sanjayxr_12_/">Instagram</a>.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop a CRUD App with Spring Boot, Neon Postgres, and Azure App Service ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and Neon Postgres. We'll also deploy the application on Azure App Service and make it production-ready by setting up features like autos... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-crud-app-spring-boot-neon-postgres/</link>
                <guid isPermaLink="false">66c3762340438b5931fe0a0b</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhinav Pandey ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jul 2024 19:14:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/neon-banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and <a target="_blank" href="https://neon.tech/">Neon Postgres</a>.</p>
<p>We'll also deploy the application on <a target="_blank" href="https://azure.microsoft.com/en-us/products/app-service">Azure App Service</a> and make it production-ready by setting up features like autoscaling and multiple environments.</p>
<p>You'll learn how Neon Postgres can make your development and deployment processes easier along the way.</p>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ul>
<li>Setting up a Neon Postgres database and exploring its features</li>
<li>Building a CRUD application using Spring Boot and deploying the application on Azure App Service</li>
<li>Why Neon is a good fit for infrastructure that auto-scales</li>
<li>Database branching in Neon Postgres and how it can ease the development workflow</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Working knowledge of Java, Maven, and Spring Boot</li>
<li>Basics of SQL databases</li>
<li>Understanding of serverless and cloud services</li>
<li>Familiarity with testing and deployment processes</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-neon-postgres">What is Neon Postgres?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-database">How to Set Up the Database</a><ul>
<li><a class="post-section-overview" href="#heading-create-the-database">Create the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</a><ul>
<li><a class="post-section-overview" href="#heading-create-an-entity-class">Create an Entity Class</a></li>
<li><a class="post-section-overview" href="#heading-create-a-repository">Create a Repository</a></li>
<li><a class="post-section-overview" href="#heading-create-a-rest-controller">Create a REST Controller</a></li>
<li><a class="post-section-overview" href="#heading-configure-the-database">Configure the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</a><ul>
<li><a class="post-section-overview" href="#heading-create-a-new-web-app">Create a New Web App</a></li>
<li><a class="post-section-overview" href="#heading-deploy-the-application">Deploy the Application</a></li>
<li><a class="post-section-overview" href="#heading-access-the-application">Access the Application</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</a><ul>
<li><a class="post-section-overview" href="#heading-autoscaling-in-azure">Autoscaling in Azure</a></li>
<li><a class="post-section-overview" href="#heading-autoscaling-in-neon">Autoscaling in Neon</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ul>
<h2 id="heading-what-is-neon-postgres">What is Neon Postgres?</h2>
<p>Neon is a fully managed serverless Postgres database platform. It offers features such as high availability, automatic backups, and scaling options to handle varying traffic levels.</p>
<p>Neon is designed to be cost-efficient and developer-friendly, and it focuses on providing a seamless experience for developers.</p>
<p>In addition to the standard Postgres features, it provides capabilities like database branching, allowing you to create Git-like branches of the database for different purposes.</p>
<h2 id="heading-how-to-set-up-the-database">How to Set Up the Database</h2>
<p>To begin with, let's explore how you can set up a Neon database for your application.</p>
<p>Firstly, you'll need to <a target="_blank" href="https://console.neon.tech/signup">create an account</a> on the Neon website. It doesn't require a credit card to sign up, and you're automatically set up with the free tier to get started.</p>
<p>Here's a <a target="_blank" href="https://neon.tech/pricing">pricing and features comparison</a> of Neon plans:</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finxumg46sf92ffre6l2q.png" alt="A screenshot of pricing plans in Neon listing down free and paid features" width="600" height="400" loading="lazy">
<em>Neon pricing plans</em></p>
<p>In the free tier, we get 0.5 GB of storage with basic computing which is enough for playing around with the database and building small applications.</p>
<h3 id="heading-create-the-database">Create the Database</h3>
<p>Once you've signed up, you can access the dashboard and create a new project.</p>
<p>Star by filling in the project name, region, and Postgres version options. In addition to this, we can choose two additional options:</p>
<ul>
<li><strong>compute size</strong> – You can choose a min and max compute size for the database. This is useful for autoscaling the database based on the load.</li>
<li><strong>suspend time</strong> – You can set a time after which the database will be suspended if not being used. This is useful for saving costs when the database is not being used.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggwuvqtb8ydl3mxd1dak.png" alt="Form with specifications required when creating a database" width="600" height="400" loading="lazy">
<em>Creating a database project in Neon</em></p>
<p>Once you submit the form, Neon will create the database and provide the connection details.</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2x5d81euphg2owgxhd.png" alt="Neon Dashboard showing the project is ready. Also shows connection details." width="600" height="400" loading="lazy">
<em>Neon Dashboard</em></p>
<p>As you can see, the database was set up in 3.3 seconds (compared to hours of installing and setting up your own infrastructure). You can choose multiple ways to connect to the database. For this tutorial, select Java as your programming language and get the JDBC connection string.</p>
<h2 id="heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</h2>
<p>Next, let's set up our CRUD application. We'll use Spring Boot, as it provides easy bootstrapping and configuration for building web applications.</p>
<p>We can use the <a target="_blank" href="https://start.spring.io/">Spring Initializr</a> to generate a new Spring Boot project with the necessary dependencies:</p>
<ul>
<li>Spring Web – for building web applications</li>
<li>Spring Data JPA – for working with databases using JPA</li>
<li>PostGres Driver – for connecting to the Postgres database</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffifv17tc5d3swothe3zf.png" alt="Spring Initializer website form to select spring boot project specifications and dependencies" width="600" height="400" loading="lazy">
<em>Creating a Spring Boot project using Spring Initializer</em></p>
<p>You can generate, download, and import the project into your favorite IDE.</p>
<h3 id="heading-create-an-entity-class">Create an Entity Class</h3>
<p>Let's create an entity class to represent the data in the application. First, create a <code>User</code> class:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Entity(name = "users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String email;

    <span class="hljs-comment">// Constructors, Getters and Setters</span>
}
</code></pre>
<p>The entity name <code>users</code> is the name of the table you want to use in your database.</p>
<h3 id="heading-create-a-repository">Create a Repository</h3>
<p>Next, create a repository interface to interact with the database. You'll extend the <code>JpaRepository</code> interface provided by Spring Data JPA:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Repository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">Long</span>&gt; </span>{
}
</code></pre>
<p>You need to annotate the interface with <code>@Repository</code> to mark it as a Spring bean. The <code>JpaRepository</code> interface provides methods for CRUD operations like <code>save</code>, <code>findAll</code>, <code>findById</code>, <code>delete</code>, and so on, so you don't need to write the queries manually.</p>
<p>You'll provide your entity class <code>User</code> and the type of the primary key <code>Long</code> as type arguments to the <code>JpaRepository</code> interface.</p>
<h3 id="heading-create-a-rest-controller">Create a REST Controller</h3>
<p>Finally, create a REST controller to handle the CRUD operations. You'll inject the <code>UserRepository</code> into the controller and implement the necessary endpoints:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span><span class="hljs-params">(UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-meta">@GetMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">getUsers</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findAll();
    }

    <span class="hljs-meta">@PostMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">createUser</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@PutMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">updateUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id, <span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        user.setId(id);
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@DeleteMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id)</span> </span>{
        userRepository.deleteById(id);
    }
}
</code></pre>
<p>Here are a few things to note:</p>
<ul>
<li>You're using the <code>@RestController</code> annotation to mark the class as a controller that handles REST requests.</li>
<li>The <code>@RequestMapping</code> annotation specifies the base URL for the endpoints.</li>
<li>You're injecting the <code>UserRepository</code> into the controller using constructor injection.</li>
<li>Finally, you're implementing your API endpoints for CRUD operations using the <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>, and <code>@DeleteMapping</code> annotations.</li>
</ul>
<h3 id="heading-configure-the-database">Configure the Database</h3>
<p>To connect your Spring Boot application to the Neon Postgres database, you need to configure the database URL, username, and password in the <code>application.properties</code> file:</p>
<pre><code>spring.datasource.url=jdbc:postgresql:<span class="hljs-comment">//&lt;db-url&gt;/&lt;db-name&gt;?sslmode=require</span>
spring.datasource.username=&lt;username&gt;
spring.datasource.password=&lt;password&gt;
spring.jpa.hibernate.ddl-auto=update
</code></pre><p>Here, you configured the database URL, username, and password provided by Neon when you created the database. The <code>spring.jpa.hibernate.ddl-auto=update</code> property tells Spring Boot to automatically create the necessary tables or columns based on the entity classes when the application starts.</p>
<h2 id="heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</h2>
<p>Now that your Spring Boot application is ready, it's time to deploy it on Azure App Service.</p>
<h3 id="heading-create-a-new-web-app">Create a New Web App</h3>
<p>To deploy your Spring Boot application on Azure App Service, you'll first create a new <code>Web App</code>. You can do this through the Azure portal by following these steps:</p>
<ul>
<li>Log in to the <a target="_blank" href="https://portal.azure.com/">Azure portal</a>.</li>
<li>Click on the <code>Create a resource</code> button.</li>
<li>Search for <code>Web App</code> and select the <code>Create</code> option.</li>
<li>Fill in the necessary details like resource group, app name, runtime stack, and region.</li>
<li>Click the <code>Review + create</code> button.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf2kmh12t8eucd1qa1pg.png" alt="Form for creating a web app in Azure" width="600" height="400" loading="lazy">
<em>Creating a Web App in Azure</em></p>
<h3 id="heading-deploy-the-application">Deploy the Application</h3>
<p>The Web App takes a couple of minutes to create. Once done, you can deploy your Spring Boot application to Azure App Service.</p>
<p>One of the easiest ways to deploy is to package your Spring Boot application as a JAR file and deploy it to Azure App Service using the Azure CLI.</p>
<p>To do this, run the below commands:</p>
<pre><code>mvn package
az webapp deploy --src-path neon-demo<span class="hljs-number">-0.0</span><span class="hljs-number">.1</span>-SNAPSHOT.jar --resource-group learn-ba1a439c<span class="hljs-number">-71</span>ca<span class="hljs-number">-4</span>cab<span class="hljs-number">-9</span>bb1-f5b1331bab04 --name neon-app
</code></pre><p>Here, you're packaging your Spring Boot application using Maven and deploying the JAR file to Azure App Service using the Azure CLI. You've provided the path to the JAR file, the resource group, and the app name you previously configured.</p>
<h3 id="heading-access-the-application">Access the Application</h3>
<p>Once the deployment is complete, you can access your Spring Boot application on Azure App Service by navigating to the URL of the Web App. Your app is available at neon-app.azurewebsites.net</p>
<p>Let's use _curl _to test the endpoints.</p>
<h4 id="heading-create-a-user">Create a User</h4>
<pre><code>curl -X POST -d <span class="hljs-string">'{"name":"John Doe","email":"john@gmail.com"}'</span> https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><p>Here you provide user data in JSON format to create a new user.</p>
<h4 id="heading-get-users">Get Users</h4>
<p>You can also can test that the user was created by fetching all users:</p>
<pre><code>curl -X GET https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><h2 id="heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</h2>
<p>A production application may experience varying levels of traffic, and it's important to scale the application dynamically based on the load.</p>
<p>Let's explore how you can autoscale your application when needed.</p>
<h3 id="heading-autoscaling-in-azure">Autoscaling in Azure</h3>
<p>Azure App Service provides <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal#plan-and-sku-settings">autoscaling options</a> that let you automatically adjust the number of instances as needed.</p>
<p>You can configure autoscaling rules in the Azure portal by following these steps:</p>
<ul>
<li>Navigate to the Web App in the Azure portal.</li>
<li>Click the <code>Scale out (App Service Plan)</code> option from the left menu.</li>
<li>Configure the autoscaling rules – you can choose predefined rules like traffic or create custom rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
<li>Save.</li>
</ul>
<p>Azure will automatically scale the application based on the configured rules.</p>
<h3 id="heading-autoscaling-in-neon">Autoscaling in Neon</h3>
<p>Since your application is automatically scaled based on the load, you'll want to ensure that the database can handle the increased traffic.</p>
<p>Neon provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">autoscaling options</a> to scale the database dynamically based on the load. You can configure autoscaling rules in the Neon dashboard to ensure the database can handle the increased load.</p>
<p>Follow the below steps to configure autoscaling in Neon:</p>
<ol>
<li>Navigate to the Neon dashboard and select the database. Then select the branch to configure autoscaling.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6s84pqhk2avflpjbgrf.png" alt="Neon project dashboard with branches section highlighted " width="600" height="400" loading="lazy">
<em>Selecting a branch from Neon project dashboard</em></p>
<ol start="2">
<li>Click on the <code>Edit</code> button next to the <code>Compute</code> section. Configure the autoscaling rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkn11nop1zz9xxbfamsr.png" alt="Branch details view in Neon with edit button in the computes section highlighted" width="600" height="400" loading="lazy">
<em>Branch details view in Neon</em></p>
<ol start="3">
<li>Configure the min-max compute size and Save. Neon will automatically scale the database based on the configured rules when needed.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmuow8zvndz0dibv2kxt.png" alt="Form to enable autoscaling and select min and max size of the compute" width="600" height="400" loading="lazy">
<em>Setting up autoscaling for compute</em></p>
<p>Ensuring that both the application and the database can scale dynamically based on the load will help you handle varying levels of traffic efficiently.</p>
<h2 id="heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</h2>
<p>In a typical development workflow, multiple databases may be used for different purposes like development, testing, and production.</p>
<p>Neon Postgres provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">database branching</a> to create multiple branches for different purposes. Each branch is an instance of the database that you can use independently.</p>
<p>This Git-like feature helps set up a copy of the database for different environments like development, staging, and production. It also helps preserve data for different versions of the application.</p>
<p>Let's explore how you can create and manage branches in Neon Postgres:</p>
<ul>
<li>Navigate to the Neon dashboard and select the database.</li>
<li>In the <code>Branches</code> section, click on the <code>View All</code> button.</li>
<li>You can create a new branch from an existing one by clicking on the <code>Create Branch</code> button. You'll need to provide the branch name and what data to copy from the parent branch.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ncdgdrj32etd3gbqurf.png" alt="Branches view with Create branch option visible " width="600" height="400" loading="lazy">
<em>Create branch option</em></p>
<ul>
<li>You can either copy all the data or copy until a point in time or a specific record. This is useful for multiple purposes like restoring data, creating a new environment, or testing new features.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7gchucru5qw294icqw3.png" alt="Creating a new branch from an existing branch" width="600" height="400" loading="lazy">
<em>Creating a new branch</em></p>
<ul>
<li>Neon will create a new branch of the database that can be used independently. You can find the URL, username, and password for the new branch in the dashboard. And this happens in real time without any downtime and delays.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji79akuf193gtv94yaag.png" alt="Branch-specific connection details " width="600" height="400" loading="lazy">
<em>Branch-specific connection details</em></p>
<p>Now you can use your <code>dev</code> branch for local development and testing, and the <code>main</code> branch for production. This helps in keeping the data separate and ensures that changes in one branch do not affect the other branches.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we built a CRUD application using Spring Boot, Neon Postgres, and Azure App Service.</p>
<p>We explored how to set up the Neon Postgres database, build a basic CRUD application using Spring Boot, deploy the application on Azure App Service, and configure autoscaling for the application and the database.</p>
<p>We also learned about how the database branching feature in Neon Postgres helps you create branches of the database for different environments and purposes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build CRUD Operations with .NET Core – A Todo API Handbook ]]>
                </title>
                <description>
                    <![CDATA[ Welcome to this comprehensive guide on building CRUD operations with .NET Core. We'll use a Todo API as our practical example so you can get hands-on experience as you learn.  Throughout this tutorial, you'll learn how to create, read, update, and de... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-crud-operations-with-dotnet-core-handbook/</link>
                <guid isPermaLink="false">66bb56fb3c5ab240beb8cd95</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ .net core ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Fri, 24 May 2024 14:33:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/Attractive.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Welcome to this comprehensive guide on building CRUD operations with .NET Core. We'll use a Todo API as our practical example so you can get hands-on experience as you learn. </p>
<p>Throughout this tutorial, you'll learn how to create, read, update, and delete Todo items, and how to leverage Entity Framework Core to interact with a database.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-enhance-your-development-experience-with-visual-studio-code-extensions">How to Enhance Your Development Experience with Visual Studio Code Extensions</a></li>
<li><a class="post-section-overview" href="#heading-learning-outcomes">Learning Outcomes</a></li>
<li><a class="post-section-overview" href="#heading-what-is-net-core">What is .NET Core?</a></li>
<li><a class="post-section-overview" href="#heading-net-core-vs-net-framework">.NET Core vs .NET Framework</a></li>
<li><a class="post-section-overview" href="#heading-step-1-set-up-your-project-directory">Step 1: Set Up Your Project Directory</a></li>
<li><a class="post-section-overview" href="#heading-step-2-establish-your-project-structure">Step 2: Establish Your Project Structure</a></li>
<li><a class="post-section-overview" href="#heading-step-3-create-the-todo-model">Step 3: Create the Todo Model</a></li>
<li><a class="post-section-overview" href="#heading-step-4-set-up-the-database-context">Step 4: Set Up the Database Context</a></li>
<li><a class="post-section-overview" href="#heading-step-5-define-data-transfer-objects-dtos">Step 5: Define Data Transfer Objects (DTOs)</a></li>
<li><a class="post-section-overview" href="#heading-step-6-implement-object-mapping-for-the-todo-api">Step 6: Implement Object Mapping for the Todo API</a></li>
<li><a class="post-section-overview" href="#heading-step-7-implement-global-exception-handling-middleware">Step 7: Implement Global Exception Handling Middleware</a>  </li>
<li><a class="post-section-overview" href="#heading-step-8-implement-the-service-layer-and-service-interface">Step 8: Implement the Service Layer and Service Interface</a></li>
<li><a class="post-section-overview" href="#heading-step-9-implement-the-createtodoasync-method-in-the-todoservices-class">step 9: Implement the CreateTodoAsync Method in the Service Class</a> </li>
<li><a class="post-section-overview" href="#heading-step-10-implement-the-getallasync-method-in-the-service-class">Step 10: Implement the GetAllAsync Method in the Service Class</a> </li>
<li><a class="post-section-overview" href="#heading-step-11-create-the-todocontroller-class">step 11: Create the TodoController Class  </a> </li>
<li><a class="post-section-overview" href="#step-12">Step 12: Implement the CreateTodoAsync  Method in the TodoController Class</a></li>
<li><a class="post-section-overview" href="#heading-step-13-implement-migrations-and-update-the-database">Step 13: Implement Migrations and Update the Database</a></li>
<li><a class="post-section-overview" href="#heading-step-14-verify-your-api-with-postman">Step 14: Verify Your API with Postman</a></li>
<li><a class="post-section-overview" href="#heading-step-15-retrieve-all-todo-items">Step 15: Retrieve All Todo Items</a> </li>
<li><a class="post-section-overview" href="#heading-step-16-implement-the-getbyidasync-method">Step 16: Implement the GetByIdAsync Method</a></li>
<li><a class="post-section-overview" href="#heading-step-17-implement-the-updatetodoasync-method">Step 17: Implement the UpdateTodoAsync Method</a></li>
<li><a class="post-section-overview" href="#heading-step-18-implement-the-deletetodoasync-method">Step 18: Implement the DeleteTodoAsync Method</a></li>
<li><a class="post-section-overview" href="#heading-step-19-test-your-api-endpoints-with-postman">Step 19: Test Your API Endpoints with Postman</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<p>Before we dive in, let's ensure you're equipped with the necessary prerequisites.</p>
<h2 id="prerequisites">Prerequisites</h2>

<p>Before you get started, make sure you have the necessary tools installed on your machine. Here are the download links:</p>
<ul>
<li><a target="_blank" href="https://dotnet.microsoft.com/download">.NET SDK</a></li>
<li><a target="_blank" href="https://code.visualstudio.com/download">Visual Studio Code</a></li>
<li><a target="_blank" href="https://visualstudio.microsoft.com/downloads/">Visual Studio 2019</a></li>
<li><a target="_blank" href="https://www.postman.com/downloads/">Postman</a></li>
<li><a target="_blank" href="https://www.microsoft.com/en-us/sql-server/sql-server-downloads">SQLServer</a></li>
</ul>
<p>After installing the .NET SDK, it's important to verify its installation and check the version. For this tutorial, we'll be using .NET 8.0.</p>
<p>To check the version of the .NET SDK installed on your machine, open the terminal and run the following command:</p>
<pre><code class="lang-bash">dotnet --version
</code></pre>
<p>If the .NET SDK is installed correctly, the version number will be displayed in the terminal:</p>
<pre><code class="lang-bash">8.0
</code></pre>
<p>If you see a different version number, ensure you have .NET 8.0 installed on your machine.</p>
<h2 id="enhancing-development"> How to Enhance Your Development Experience with Visual Studio Code Extensions</h2>

<p>Visual Studio Code, a lightweight and open-source code editor, is an excellent tool for building .NET Core applications. And you can further enhance its functionality with extensions that streamline the development process. </p>
<p>Here are two recommended extensions for .NET Core development:</p>
<ul>
<li><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit">C# for Visual Studio Code</a></li>
<li><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=adrianwilczynski.namespace">C# Namespace Autocompletion</a></li>
</ul>
<p>To install these extensions, follow these steps:</p>
<ol>
<li>Open Visual Studio Code.</li>
<li>Click on the Extensions icon in the Activity Bar on the side of the window to open the Extensions view.</li>
<li>In the search bar, type the name of the extension.</li>
<li>In the search results, locate the correct extension and click on the Install button.</li>
</ol>
<p>Here's how the Extensions view looks in Visual Studio Code:</p>
<ul>
<li><p>C# Devkit Extension for Visual Studio Code
<img src="https://www.freecodecamp.org/news/content/images/2024/05/DevKIt.png" alt="Extensions view for Devkit" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Namespace Autocompletion Extension for Visual Studio Code
<img src="https://www.freecodecamp.org/news/content/images/2024/05/NameSpace.png" alt="Extensions view for Namespace Autocompletion" width="600" height="400" loading="lazy"></p>
</li>
</ul>
<p>In the images above, the extensions are already installed. If they're not installed on your system, you can do so by clicking on the Install button.</p>
<p>With these essential tools in place, we're now fully equipped to start building our Todo API.</p>
<h2 id="learning-outcomes"> Learning Outcomes </h2>


<p>By the end of this tutorial, you'll have learned how to:</p>
<ul>
<li>Set up a new .NET Core project using the .NET Core CLI</li>
<li>Define a model for a Todo item</li>
<li>Create a database context to interact with the database</li>
<li>Implement routing and controllers for the Todo API</li>
<li>Create a service class to handle business logic</li>
<li>Implement CRUD operations for the Todo API</li>
<li>Handle exceptions globally using middleware</li>
<li>Test the API endpoints using Postman</li>
</ul>
<p>If you're new to C# and .NET, don't worry. I'll explain all the concepts in depth to ensure you understand them. For additional information, you can refer to the <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/csharp/">C# documentation</a>.</p>
<p>Before we delve into the code, let's clarify what .NET Core is.</p>
<h2 id="what-is-net-core"> What is .NET Core? </h2>

<p>.NET Core, also known as ASP.NET, is a cross-platform framework that facilitates the building of web applications, APIs, and services. It's a free, open-source, and high-performance framework, designed for creating modern, cloud-based, internet-connected applications. It's the successor to the .NET Framework.</p>
<p>But what's the difference between .NET Core and .NET Framework?</p>
<h2 id="net-core-vs-net-framework"> .NET Core vs .NET Framework </h2>

<p>.NET Core and .NET Framework are two distinct frameworks used for application development. .NET Core is a cross-platform framework that operates on Windows, macOS, and Linux. It's a modular, open-source, and free-to-use framework, designed for building modern, cloud-based, internet-connected applications.</p>
<p>On the other hand, <code>.NET Framework</code> is a <code>Windows-only framework</code> used for building <code>Windows desktop</code> <code>applications</code>, <code>web applications</code>, and services. Unlike .NET Core, it's not open-source or free to use. However, it's a mature framework that has been around for a long time.</p>
<p>With a foundational understanding of .NET Core and .NET Framework under your belt, we're ready to dive into building our Todo API.</p>
<p>In this tutorial, we'll leverage .NET Core to construct a Todo API that performs CRUD operations. Our journey will take us through creating a new project, defining the Todo model, setting up the database, and implementing the CRUD operations.</p>
<p>Let's begin with Visual Studio Code. In this tutorial, we'll be using the .NET Core CLI to create our project and build our API. If you prefer Visual Studio 2019, you can follow along using that IDE as well but we will be using Visual Studio Code for this article. </p>
<h2 id="step-1">  Step 1: Set Up Your Project Directory </h2>

<p>First, navigate to the directory where you want to house your project. This could be any folder on your system where you'd like to store your code.</p>
<p>Once you're in the desired directory, open the terminal. You can do this in Visual Studio Code by going to <code>View -&gt; Terminal</code> or by pressing Ctrl + a  backtick.</p>
<p>With the terminal open, type the following command:</p>
<pre><code class="lang-bash">dotnet new webapi -n TodoAPI
</code></pre>
<p>This command instructs the .NET Core CLI to create a new web API project named <code>TodoAPI</code>. The <code>-n</code> option specifies the name of the project.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2024/05/TerminalCreatingNewAPI.png" alt="Creating a new API with the .NET Core CLI" width="600" height="400" loading="lazy"></p>
<p>The image above illustrates how to execute the command in the terminal.</p>
<p>After pressing the 'Enter' key, the .NET Core CLI will start generating the necessary files for your project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/ProjectFile.png" alt=".NET project folder structure" width="600" height="400" loading="lazy"></p>
<p>The image above showcases the generated project structure. It includes all the necessary files and directories required for a .NET Core web API project.</p>
<p>With the project files and folders generated by the .NET Core CLI, let's take a moment to understand the purpose of each file.</p>
<ul>
<li><p><code>appsettings.json</code>: This file houses the application's configuration settings. It's the go-to place for storing connection strings, logging configurations, and other settings.</p>
</li>
<li><p><code>Program.cs</code>: Serving as the application's entry point, this file is responsible for setting up the host and configuring the services.</p>
</li>
<li><p><code>TodoAPI.csproj</code>: This project file contains metadata about your project, including references to the necessary packages and libraries.</p>
</li>
<li><p><code>appsettings.Development.json</code>: This file is designed for configuration settings specific to the development environment. It's ideal for storing environment-specific settings. But for the purpose of this tutorial, we'll be using the <code>appsettings.json</code> file instead.</p>
</li>
<li><p><code>TodoAPI.http</code>: This file is typically used to test API endpoints using the REST Client extension in Visual Studio Code, as it contains sample requests for the API endpoints. However, in this tutorial, we'll be using Postman for testing, so we won't need this file and will proceed to delete it.</p>
</li>
</ul>
<h2 id="step-2">  Step 2: Establish Your Project Structure  </h2>

<p>Having set up our project directory, it's time to lay out the structure of our project. We'll be creating several folders, each with a specific purpose:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/ProjectFolder.png" alt="project folder structure" width="600" height="400" loading="lazy"></p>
<ul>
<li><code>AppDataContext</code>: This folder will contain the database context, which is responsible for interacting with the database.</li>
<li><code>Contracts</code>: This folder will house our Data Transfer Objects (DTOs), which are used to shape the data sent between the client and the server.</li>
<li><code>Models</code>: This folder will contain the Todo model, which represents the structure of a Todo item.</li>
<li><code>Controllers</code>: This folder will house the TodoController, which handles incoming HTTP requests and sends responses.</li>
<li><code>Interfaces</code>: This folder will contain the IService interface, which defines the contract for our service class.</li>
<li><code>Services</code>: This folder will house the Service class, which implements the IService interface and contains the business logic of our application.</li>
<li><code>Mapping</code>: This folder will contain the mapping profile, which is used to map properties between different objects.</li>
<li><code>Middleware</code>: This folder will house the exception middleware, which handles exceptions globally across our application.</li>
</ul>
<p><em>Congratulations!</em> You've successfully set up your project directory and established the project structure. In the next section, we'll delve into defining the Todo model.</p>
<h3 id="heading-how-to-adjust-the-programcs-file-for-controllerbase">   How to Adjust the Program.cs File for ControllerBase </h3>

<p>When creating a new application using the <code>dotnet new webapi</code> command in .NET Core 6 and onwards, the generated project is a minimal web API project. But for this tutorial, we'll be using the traditional way of creating APIs, which requires some adjustments to the <code>Program.cs</code> file.</p>
<p>Before we dive into the changes, let's briefly discuss what a minimal API is.</p>
<h3 id="heading-understanding-minimal-apis">  Understanding Minimal APIs </h3>

<p>In .NET 6, Microsoft introduced a new feature known as Minimal APIs. These APIs are simpler and more lightweight than traditional APIs. They allow you to define your API routes and endpoints using a single file, without the need for controllers or startup classes. This approach facilitates the creation of small, focused APIs that are quick to build and easy to maintain.</p>
<p>However, for the purpose of this tutorial, we'll stick to the traditional API structure. Let's proceed with the necessary changes to the <code>Program.cs</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/Program.cs.png" alt="Initial view of Program.cs" width="600" height="400" loading="lazy"></p>
<p>The image above displays the initial state of the <code>Program.cs</code> file when you create a new web API project. To adapt it for use with ControllerBase, we need to remove some code and add new code.</p>
<p>Start by deleting everything in the <code>Program.cs</code> file and replacing it with the following code:</p>
<pre><code class="lang-csharp">
 <span class="hljs-comment">// program.cs</span>
<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Add services to the container.</span>
builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Configure the HTTP request pipeline.</span>
<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
</code></pre>
<p>Now we can proceed to the next step, where we'll define the Todo model.</p>
<h2 id="step-3">  Step 3: Create the Todo Model  </h2>

<p>Before diving into creating our Todo model, it's important to know what a model does in <code>.NET CORE</code>. Think of a <code>model</code> as a <code>blueprint</code> for the kind of data our application will work with. It helps us organize and manage this data efficiently.</p>
<p>For our Todo list app, we need a clear picture of what each Todo item looks like. This means deciding on things like names, descriptions, whether it's done or not, deadlines, priorities, and when it was made or changed. By being clear about these details, we can handle and show our Todo items well.</p>
<h3 id="heading-meet-the-todo-model">  Meet the Todo Model </h3>

<p>Now, let's make our idea real by creating the <code>Todo</code> model. This model is like a template for our Todo items, making sure they have all the right pieces.</p>
<p>Let's create a new file called <code>Todo.cs</code> in the <code>Models</code> folder and fill it with this code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Models/Todo.cs</span>
<span class="hljs-keyword">using</span> System.ComponentModel.DataAnnotations;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Models</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Todo</span>
    {
        [<span class="hljs-meta">Key</span>]
        <span class="hljs-keyword">public</span> Guid Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> IsComplete { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> DateTime DueDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Priority { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> DateTime CreatedAt { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> DateTime UpdatedAt { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>)</span>
        {
            IsComplete = <span class="hljs-literal">false</span>;
        }
    }
}
</code></pre>
<p>Here's what each part of the <code>Todo</code> model means:</p>
<ul>
<li><strong>Id</strong>: A special number that makes each Todo item unique.</li>
<li><strong>Title</strong>: The name of the Todo item.</li>
<li><strong>Description</strong>: Extra details about the Todo item.</li>
<li><strong>IsComplete</strong>: Whether the Todo item is finished or not.</li>
<li><strong>DueDate</strong>: The date by which the Todo item needs to be done.</li>
<li><strong>Priority</strong>: How important the Todo item is.</li>
<li><strong>CreatedAt</strong> and <strong>UpdatedAt</strong>: When the Todo item was first made and last changed.</li>
</ul>
<p>The <code>[Key]</code> tag tells us that <code>Id</code> is the main way to identify each Todo item in our database.</p>
<p>By having a clear <code>Todo</code> model, we can easily keep track of and display our Todo items in the best way possible.</p>
<p>In ASP.NET Core, models can be used to represent a variety of things. One such use case is error handling. When an error occurs in our application, we can create a model for that error and return it to the client. </p>
<p>Let's create a model specifically for error handling in our application.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Models/ErrorResponse.cs</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Models</span>
{
       <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ErrorResponse</span>
 {
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> StatusCode { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Message { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 }
}
</code></pre>
<p>This ErrorResponse model will be used to return error messages to the client when an error occurs in our application. It includes a title for the error, massage, and a status code, providing the client with useful information about what went wrong.</p>
<p>Let's define another model to manage our database connection string.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Models/DbSettings.cs </span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Models</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DbSettings</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ConnectionString { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>The <code>DbSettings</code> model is designed to encapsulate the connection string for our database. It contains a single property, <code>ConnectionString</code>, which will store the actual connection string value.</p>
<p>With our <code>Todo</code> model in place, we're now ready to proceed with setting up the database context.</p>
<p>Before we begin setting up our database, we need to install the necessary packages for our project.</p>
<h3 id="heading-package-installation">   Package Installation </h3>


<p>To set up our project, we need to install several packages. We'll use the dotnet CLI for this task. </p>
<p>Before we begin, ensure you're in the root directory of your project. If you're unsure of your current location in the terminal, you can verify it by running the following command:</p>
<pre><code class="lang-bash">ls
</code></pre>
<p>This command will list all the files and folders in your current directory. The image below shows the terminal output after running the <code>ls</code> command.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/ls-terminal.png" alt="Terminal ls file" width="600" height="400" loading="lazy"></p>
<p>If your terminal output matches the image above, you're in the correct directory to install the packages.</p>
<p>Now, let's install the packages:</p>
<pre><code class="lang-bash">dotnet add package Microsoft.EntityFrameworkCore --version 8.0.0 
dotnet add package Microsoft.EntityFrameworkCore.Design --version 8.0.0
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 8.0.0
dotnet add package AutoMapper --version 13.0.1
</code></pre>
<p>Here's a brief overview of what these packages do:</p>
<ul>
<li><code>Microsoft.EntityFrameworkCore</code>: Provides the core Entity Framework Core functionality, enabling us to interact with our database.</li>
<li><code>Microsoft.EntityFrameworkCore.Design</code>: Includes design-time components for Entity Framework Core, such as migrations.</li>
<li><code>Microsoft.EntityFrameworkCore.SqlServer</code>: Allows us to use SQL Server as our database provider.</li>
<li><code>AutoMapper</code>: Simplifies object-to-object mapping, making it easier to map properties between different objects.</li>
</ul>
<p><strong>Note</strong>: Ensure you install the same versions of the packages as shown above to avoid any compatibility issues.</p>
<p>To confirm that all the packages have been installed successfully, navigate to the <code>TodoAPI.csproj</code> file located in the root directory of your project. The installed packages should be listed under the <code>ItemGroup</code> section.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net8.0<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Nullable</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">Nullable</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ImplicitUsings</span>&gt;</span>enable<span class="hljs-tag">&lt;/<span class="hljs-name">ImplicitUsings</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">InvariantGlobalization</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">InvariantGlobalization</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"AutoMapper"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"13.0.1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.AspNetCore.OpenApi"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.Design"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.0"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.EntityFrameworkCore.SqlServer"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"8.0.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Swashbuckle.AspNetCore"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"6.4.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<p>The above <code>TodoAPI.csproj</code> file shows the installed packages listed under the <code>ItemGroup</code> section. If your <code>TodoAPI.csproj</code> file reflects the same, it confirms that the packages have been installed successfully.</p>
<p>With the necessary packages installed, we're now ready to set up the database context for our Todo API.</p>
<h2 id="step-4">  Step 4: Set Up the Database Context  </h2>

<p>In ASP.NET Core, the database context is a crucial component that manages interactions with the database. It's responsible for tasks such as establishing a connection to the database, querying data, and saving changes. </p>
<p>To enable our <code>Todo API</code> to interact with the database, we need to create a database context.</p>
<p>Let's create a new file named <code>TodoDbContext</code> in the <code>AppDataContext</code> folder and populate it with the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// AppDataContext/TodoDbContext.cs</span>

<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> Microsoft.Extensions.Options;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.AppDataContext</span>
{

    <span class="hljs-comment">// TodoDbContext class inherits from DbContext</span>
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoDbContext</span> : <span class="hljs-title">DbContext</span>
     {

        <span class="hljs-comment">// DbSettings field to store the connection string</span>
         <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> DbSettings _dbsettings;

            <span class="hljs-comment">// Constructor to inject the DbSettings model</span>
         <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoDbContext</span>(<span class="hljs-params">IOptions&lt;DbSettings&gt; dbSettings</span>)</span>
         {
             _dbsettings = dbSettings.Value;
         }


        <span class="hljs-comment">// DbSet property to represent the Todo table</span>
         <span class="hljs-keyword">public</span> DbSet&lt;Todo&gt; Todos { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

         <span class="hljs-comment">// Configuring the database provider and connection string</span>

         <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnConfiguring</span>(<span class="hljs-params">DbContextOptionsBuilder optionsBuilder</span>)</span>
         {
             optionsBuilder.UseSqlServer(_dbsettings.ConnectionString);
         }

            <span class="hljs-comment">// Configuring the model for the Todo entity</span>
         <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder modelBuilder</span>)</span>
         {
             modelBuilder.Entity&lt;Todo&gt;()
                 .ToTable(<span class="hljs-string">"TodoAPI"</span>)
                 .HasKey(x =&gt; x.id);
         }
     }
}
</code></pre>
<p>Here's a breakdown of the <code>TodoDbContext</code> class:</p>
<ul>
<li><strong><code>TodoDbContext</code></strong>: This class, which inherits from <code>DbContext</code> (a part of Entity Framework Core), is the primary class that interacts with the database.</li>
<li><strong><code>_dbsettings</code></strong>: This private field stores the connection string for our database. We inject the <code>DbSettings</code> model, which we created earlier to manage the connection string, into the <code>TodoDbContext</code> class.</li>
<li><strong><code>Todos</code></strong>: This property represents the <code>Todo</code> table in our database. It's a <code>DbSet</code> of <code>Todo</code> objects, which allows us to query and save instances of <code>Todo</code>.</li>
<li><strong><code>OnConfiguring</code></strong>: This method configures the database provider and connection string. We're using SQL Server as our database provider, and the connection string is retrieved from the <code>DbSettings</code> model.</li>
<li><strong><code>OnModelCreating</code></strong>: This method configures the model for the <code>Todo</code> entity. We specify the table name, primary key, and other configurations for the <code>Todo</code> entity.</li>
</ul>
<p>To use our <code>TodoDbContext</code> for interacting with the database, we need to register it in the <code>Program.cs</code> file. This registration process is part of setting up the Dependency Injection (DI) container in .NET Core.</p>
<p>Here's how to do it:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>


<span class="hljs-keyword">using</span> TodoAPI.AppDataContext;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();



 <span class="hljs-comment">// Add  This to in the Program.cs file</span>
builder.Services.Configure&lt;DbSettings&gt;(builder.Configuration.GetSection(<span class="hljs-string">"DbSettings"</span>)); <span class="hljs-comment">// Add this line</span>
builder.Services.AddSingleton&lt;TodoDbContext&gt;(); <span class="hljs-comment">// Add this line</span>




<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Add this line</span>

{
    <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> scope = app.Services.CreateScope(); <span class="hljs-comment">// Add this line</span>
    <span class="hljs-keyword">var</span> context = scope.ServiceProvider; <span class="hljs-comment">// Add this line</span>
}


<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseExceptionHandler();
app.UseAuthorization();

app.MapControllers();

app.Run();
</code></pre>
<p>In the code snippet above, we're doing two things:</p>
<ul>
<li>Configuring the database settings by binding the <code>DbSettings</code> section from the <code>appsettings.json</code> file to the <code>DbSettings</code> class. This allows us to access the database connection string in our application.</li>
<li>Registering the <code>TodoDbContext</code> with the DI container as a singleton service. This means that a single instance of <code>TodoDbContext</code> will be created and shared across the entire application.</li>
</ul>
<p>With the database context registered, we can now use it to perform CRUD operations on our Todo items.</p>
<p>Now let's check if everything is working fine by running the application.</p>
<pre><code class="lang-bash">
dotnet run
</code></pre>
<p>If you see the following output, it means your application is running successfully:</p>
<pre><code class="lang-bash">
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5086
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: E:\Todo\TodoAPI
</code></pre>
<p><strong>Note</strong>: If you encounter any errors, just make sure you've followed all the steps correctly and that the necessary packages have been installed successfully. If you see some warnings, you can ignore them for now.</p>
<p>With the <code>TodoDbContext</code> class now set up, we're ready to define the Contracts  for our application.</p>
<h2 id="step-5">  Step 5: Define Data Transfer Objects (DTOs) </h2>

<p>In the context of .NET development, a Data Transfer Object (DTO) is a simple object that carries data between processes. It's often used in conjunction with a service layer to shape the data sent between the client and the server. </p>
<p>For our Todo API, we'll define two DTOs: <code>CreateTodoRequest</code> and <code>UpdateTodoRequest</code>. These DTOs will help us enforce the structure and validation of the data sent to our API.</p>
<p>Navigate to the <code>Contracts</code> folder and create two new files: <code>CreateTodoRequest.cs</code> and <code>UpdateTodoRequest.cs</code>.</p>
<h3 id="heading-the-createtodorequest-file"> The <code>CreateTodoRequest</code> File </h3>


<p>The <code>CreateTodoRequest</code> DTO will define the structure and validation rules for creating a new Todo item. Add the following code to the <code>CreateTodoRequest.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CreateTodoRequest</span>
{
    [<span class="hljs-meta">Required</span>]
    [<span class="hljs-meta">StringLength(100)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">StringLength(500)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Required</span>]
    <span class="hljs-keyword">public</span> DateTime DueDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Range(1, 5)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Priority { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>In this DTO, we've defined properties for <code>Title</code>, <code>Description</code>, <code>DueDate</code>, and <code>Priority</code>. We've also added validation attributes like <code>[Required]</code>, <code>[StringLength]</code>, and <code>[Range]</code> to enforce certain rules on these properties.</p>
<h3 id="heading-the-updatetodorequest-file"> The <code>UpdateTodoRequest</code> File </h3>


<p>The <code>UpdateTodoRequest</code> DTO will define the structure and validation rules for updating an existing Todo item. Add the following code to the <code>UpdateTodoRequest.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UpdateTodoRequest</span>
{
    [<span class="hljs-meta">StringLength(100)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">StringLength(500)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span>? IsComplete { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> DateTime? DueDate { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Range(1, 5)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span>? Priority { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UpdateTodoRequest</span>(<span class="hljs-params"></span>)</span>
    {
        IsComplete = <span class="hljs-literal">false</span>;
    }
}
</code></pre>
<p>In this DTO, we've defined properties for <code>Title</code>, <code>Description</code>, <code>IsComplete</code>, <code>DueDate</code>, and <code>Priority</code>. The <code>IsComplete</code> property is nullable, which means it can be set to <code>null</code> if not provided. We've also added validation attributes like <code>[StringLength]</code> and <code>[Range]</code> to enforce certain rules on these properties.</p>
<p>With these DTOs in place, we're now ready to implement the service layer for our Todo API.</p>
<p>Now test the application, and see if there are any errors.</p>
<pre><code class="lang-bash">
 dotnet  build
</code></pre>
<p>If you see the following output, it means your application is running successfully:</p>
<pre><code class="lang-bash">MSBuild version 17.8.3+195e7f5a3 <span class="hljs-keyword">for</span> .NET
  Determining projects to restore...
  All projects are up-to-date <span class="hljs-keyword">for</span> restore.
  TodoAPI -&gt; E:\Todo\TodoAPI\bin\Debug\net8.0\TodoAPI.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.94
</code></pre>
<p><strong>Note</strong>: If you encounter any errors, make sure you've followed all the steps correctly and that the necessary packages have been installed successfully. If you see some warnings, you can ignore them for now.</p>
<p>With the DTOs defined, we're now ready to implement the Mapping for the   Todo API.</p>
<h2 id="step-6">  Step 6: Implement Object Mapping for the Todo API </h2>

<p>Having defined the DTOs for our Todo API, the next step is to implement object mapping. This process allows us to convert between the DTOs and the Todo model, a critical aspect of data transformation in our application.</p>
<p>To streamline this process, we'll use the <code>AutoMapper</code> library. AutoMapper is a widely-used library that simplifies object-to-object mapping, making it easier to map properties between different objects.</p>
<p>We've already installed the <code>AutoMapper</code> package in our project. Now, in the <code>MappingProfiles</code> folder, create a new file named <code>AutoMapperProfile.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> AutoMapper;
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.MappingProfiles</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AutoMapperProfile</span> : <span class="hljs-title">Profile</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AutoMapperProfile</span>(<span class="hljs-params"></span>)</span>
        {
            CreateMap&lt;CreateTodoRequest, Todo&gt;()
                .ForMember(dest =&gt; dest.id, opt =&gt; opt.Ignore())
                .ForMember(dest =&gt; dest.CreatedAt, opt =&gt; opt.Ignore())
                .ForMember(dest =&gt; dest.UpdatedAt, opt =&gt; opt.Ignore());

            CreateMap&lt;UpdateTodoRequest, Todo&gt;()
                .ForMember(dest =&gt; dest.id, opt =&gt; opt.Ignore())
                .ForMember(dest =&gt; dest.CreatedAt, opt =&gt; opt.Ignore())
                .ForMember(dest =&gt; dest.UpdatedAt, opt =&gt; opt.Ignore());
        }
    }
}
</code></pre>
<p>Let's break down the <code>AutoMapperProfile</code> class:</p>
<ul>
<li><strong>AutoMapperProfile</strong>: This class, which inherits from <code>Profile</code> (a class provided by AutoMapper), allows us to define mapping configurations.</li>
<li><strong>CreateMap</strong>: This method creates a mapping between two objects. Here, we're mapping from <code>CreateTodoRequest</code> to <code>Todo</code> and from <code>UpdateTodoRequest</code> to <code>Todo</code>.</li>
<li><strong>ForMember</strong>: This method configures the mapping for a specific property. We're using it to ignore the <code>id</code>, <code>CreatedAt</code>, and <code>UpdatedAt</code> properties when mapping from the DTOs to the <code>Todo</code> model.</li>
</ul>
<p>Now let's add the automapper to the DI container in the <code>Program.cs</code> file.</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">using</span> TodoAPI.AppDataContext;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();



 <span class="hljs-comment">// Add  This to in the Program.cs file</span>
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());  <span class="hljs-comment">// Add this line</span>


<span class="hljs-comment">// .....</span>

<span class="hljs-keyword">var</span> app = builder.Build();



<span class="hljs-comment">// .....</span>
<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseExceptionHandler();
app.UseAuthorization();

app.MapControllers();

app.Run();
</code></pre>
<p>With the mapping profiles in place, we can now implement the service layer for our Todo API.</p>
<h2 id="step-7"> Step 7: Implement Global Exception Handling Middleware </h2>

<p>As we progress with our Todo API, it's crucial to implement a mechanism for handling exceptions globally. This ensures that any exceptions that occur during the execution of our application are caught and handled appropriately, providing meaningful error messages to the client.</p>
<p>.NET 8 introduces the <code>IExceptionHandler</code> interface, which simplifies the process of creating a custom exception handler. This handler will catch all exceptions that occur in our application and return a consistent error response to the client.</p>
<p>Let's create a global exception handler in the <code>Middleware</code> folder. Create a new file named <code>GlobalExceptionHandler.cs</code> and add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Middleware/GlobalExceptionHandler.cs</span>

<span class="hljs-keyword">using</span> System.Net;
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Diagnostics;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Middleware</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">GlobalExceptionHandler</span> : <span class="hljs-title">IExceptionHandler</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;GlobalExceptionHandler&gt; _logger;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GlobalExceptionHandler</span>(<span class="hljs-params">ILogger&lt;GlobalExceptionHandler&gt; logger</span>)</span>
        {
            _logger = logger;
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> ValueTask&lt;<span class="hljs-keyword">bool</span>&gt; <span class="hljs-title">TryHandleAsync</span>(<span class="hljs-params">
            HttpContext httpContext,
            Exception exception,
            CancellationToken cancellationToken</span>)</span>
        {
            _logger.LogError(
                <span class="hljs-string">$"An error occurred while processing your request: <span class="hljs-subst">{exception.Message}</span>"</span>);

            <span class="hljs-keyword">var</span> errorResponse = <span class="hljs-keyword">new</span> ErrorResponse
            {
                Message = exception.Message
            };

            <span class="hljs-keyword">switch</span> (exception)
            {
                <span class="hljs-keyword">case</span> BadHttpRequestException:
                    errorResponse.StatusCode = (<span class="hljs-keyword">int</span>)HttpStatusCode.BadRequest;
                    errorResponse.Title = exception.GetType().Name;
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">default</span>:
                    errorResponse.StatusCode = (<span class="hljs-keyword">int</span>)HttpStatusCode.InternalServerError;
                    errorResponse.Title = <span class="hljs-string">"Internal Server Error"</span>;
                    <span class="hljs-keyword">break</span>;
            }

            httpContext.Response.StatusCode = errorResponse.StatusCode;

            <span class="hljs-keyword">await</span> httpContext
                .Response
                .WriteAsJsonAsync(errorResponse, cancellationToken);

            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }
}
</code></pre>
<p>Here's a breakdown of the <code>GlobalExceptionHandler</code> class:</p>
<ul>
<li><strong>GlobalExceptionHandler</strong>: This class implements the <code>IExceptionHandler</code> interface, enabling global exception handling in our application.</li>
<li><strong>TryHandleAsync</strong>: This method is invoked when an exception occurs. It logs the error message, creates an <code>ErrorResponse</code> object, sets the status code and title based on the exception type, and returns a consistent error response to the client.</li>
<li><strong>ErrorResponse</strong>: This class represents the error response returned to the client when an exception occurs. It contains properties for the error message, status code, and title.</li>
<li><strong>BadHttpRequestException</strong>: This case handles exceptions of type <code>BadHttpRequestException</code> and sets the status code and title accordingly.</li>
</ul>
<p>After setting up the global exception handler, we need to register it in our <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">using</span> TodoAPI.AppDataContext;
<span class="hljs-keyword">using</span> TodoAPI.Interface;
<span class="hljs-keyword">using</span> TodoAPI.Middleware;
<span class="hljs-keyword">using</span> TodoAPI.Models;
<span class="hljs-keyword">using</span> TodoAPI.Services;

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);



builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();



<span class="hljs-comment">// ....</span>



builder.Services.AddExceptionHandler&lt;GlobalExceptionHandler&gt;(); <span class="hljs-comment">// Add this line</span>

builder.Services.AddProblemDetails();  <span class="hljs-comment">// Add this line</span>

<span class="hljs-comment">// Adding of login </span>
builder.Services.AddLogging();  <span class="hljs-comment">//  Add this line</span>



<span class="hljs-keyword">var</span> app = builder.Build();


<span class="hljs-comment">// ......</span>


<span class="hljs-keyword">if</span> (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection(); <span class="hljs-comment">// Add this line</span>

app.UseExceptionHandler();
app.UseAuthorization();

app.MapControllers();

app.Run();


<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="step-8"> Step 8: Implement the Service Layer and Service Interface </h2>

<p>In .NET development, the service layer encapsulates the core business logic of an application. It serves as a bridge between the controller and the database, ensuring a clean separation of concerns.</p>
<p>First, let's define an interface for our service layer.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Interfaces/ITodoServices.cs </span>

<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Interface</span>
{
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ITodoServices</span>
     {
         Task&lt;IEnumerable&lt;Todo&gt;&gt; GetAllAsync();
         <span class="hljs-function">Task&lt;Todo&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>;
         <span class="hljs-function">Task <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>;
         <span class="hljs-function">Task <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>;
         <span class="hljs-function">Task <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>;
     }
}
</code></pre>
<p>Here's a brief overview of the methods defined in the <code>ITodoServices</code> interface:</p>
<ul>
<li><code>GetAllAsync</code>: Retrieves all Todo items from the database.</li>
<li><code>GetByIdAsync</code>: Fetches a specific Todo item by its <code>Id</code>.</li>
<li><code>CreateTodoAsync</code>: Adds a new Todo item to the database.</li>
<li><code>UpdateTodoAsync</code>: Modifies an existing Todo item in the database.</li>
<li><code>DeleteTodoAsync</code>: Removes a Todo item from the database.</li>
</ul>
<p>Now, let's create a service class that implements these methods. We'll use Dependency Injection to inject the <code>ITodoServices</code> interface into the service class, making our code more modular, testable, and maintainable.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-keyword">using</span> TodoAPI.Interface;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoServices</span> : <span class="hljs-title">ITodoServices</span>
    {

    }
}
</code></pre>
<p>At this point, you'll encounter an error because we haven't implemented the methods from the <code>ITodoServices</code> interface in the <code>TodoServices</code> class. </p>
<p>The below image shows the error message that appears when the methods from the <code>ITodoServices</code> interface are not implemented in the <code>TodoServices</code> class.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/InterfaceError.png" alt="Error in the TodoServices class" width="600" height="400" loading="lazy"></p>
<p>To resolve this, hover over <code>ITodoServices</code>, click on the light bulb icon that appears, and select 'Implement interface'. This will automatically generate stubs for the methods defined in the <code>ITodoServices</code> interface.</p>
<p>The below image shows the 'Implement interface' option that appears when hovering over <code>ITodoServices</code> in the <code>TodoServices</code> class.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/QickFixt.png" alt="Implementing the ITodoServices interface" width="600" height="400" loading="lazy"></p>
<p>After implementing the interface, the <code>TodoServices</code> class should look like this:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/TodoServices.cs</span>
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Interface;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoServices</span> : <span class="hljs-title">ITodoServices</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-keyword">public</span> Task&lt;IEnumerable&lt;Todo&gt;&gt; GetAllAsync()
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;Todo&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }
    }
}
</code></pre>
<h3 id="heading-how-to-enhance-the-todoservices-class-with-dependency-injection"> How to Enhance the TodoServices Class with Dependency Injection </h3>

<p>Now, let's enrich our <code>TodoServices</code> class with some essential properties. These properties will provide the necessary tools for interacting with the database, logging, and object mapping.</p>
<p>At the top of the <code>TodoServices</code> class, add the following properties:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TodoDbContext _context;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;TodoServices&gt; _logger;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMapper _mapper;

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a brief explanation of these properties:</p>
<ul>
<li><code>_context</code>: An instance of the <code>TodoDbContext</code> class, enabling us to interact with the database.</li>
<li><code>_logger</code>: An instance of the <code>ILogger</code> class, facilitating logging throughout our application.</li>
<li><code>_mapper</code>: An instance of the <code>IMapper</code> class, allowing us to perform object-to-object mapping using AutoMapper.</li>
</ul>
<p>Next, we'll update the constructor of the <code>TodoServices</code> class to inject these dependencies:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoServices</span>(<span class="hljs-params">TodoDbContext context, ILogger&lt;TodoServices&gt; logger, IMapper mapper</span>)</span>
{
    _context = context;
    _logger = logger;
    _mapper = mapper;
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>With these dependencies injected, we're now ready to implement the methods defined in the <code>ITodoServices</code> interface. We'll begin with the <code>GetAllAsync</code> method in the next section.</p>
<h2 id="step-9"> Step 9: Implement the CreateTodoAsync Method in the TodoServices Class </h2>

<p>Now, let's implement the <code>CreateTodoAsync</code> method in the <code>TodoServices</code> class. This method will handle the creation of new Todo items in our database.</p>
<p>Navigate to the <code>TodoServices</code> class and add the following code to the <code>CreateTodoAsync</code> method:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
{
    <span class="hljs-keyword">try</span>
    {
        <span class="hljs-keyword">var</span> todo = _mapper.Map&lt;Todo&gt;(request);
        todo.CreatedAt = DateTime.UtcNow;
        _context.Todos.Add(todo);
        <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
    }
    <span class="hljs-keyword">catch</span> (Exception ex)
    {
        _logger.LogError(ex, <span class="hljs-string">"An error occurred while creating the Todo item."</span>);
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"An error occurred while creating the Todo item."</span>);
    }
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>CreateTodoAsync</code> method:</p>
<ul>
<li><strong>Mapping</strong>: We use AutoMapper to convert the <code>CreateTodoRequest</code> object into a <code>Todo</code> entity.</li>
<li><strong>CreatedAt</strong>: We set the <code>CreatedAt</code> property of the <code>Todo</code> entity to the current UTC date and time.</li>
<li><strong>Adding to the Database</strong>: We add the <code>Todo</code> entity to the <code>Todos</code> DbSet in our context and save the changes asynchronously.</li>
<li><strong>Error Handling</strong>: We catch any exceptions that might occur during the process, log the error, and throw a new exception with a descriptive error message.</li>
</ul>
<p>With the <code>CreateTodoAsync</code> method implemented, we can now create new Todo items in our database.</p>
<h2 id="step-10"> Step 10: Implement the GetAllAsync Method in the Service Class </h2>

<p>Next, let's implement the <code>GetAllAsync</code> method in the <code>TodoServices</code> class. This method will retrieve all Todo items from the database.</p>
<p>Navigate to the <code>TodoServices</code> class and add the following code to the <code>GetAllAsync</code> method:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>


 <span class="hljs-comment">// Get all TODO Items from the database </span>
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;Todo&gt;&gt; GetAllAsync()
 {
     <span class="hljs-keyword">var</span> todo= <span class="hljs-keyword">await</span> _context.Todos.ToListAsync();
     <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
     {
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">" No Todo items found"</span>);
     }
     <span class="hljs-keyword">return</span> todo;

 }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>GetAllAsync</code> method:</p>
<ul>
<li><p><strong>Retrieving Todo Items</strong>: We use Entity Framework Core's <code>ToListAsync</code> method to fetch all Todo items from the database.</p>
</li>
<li><p><strong>Error Handling</strong>: If no Todo items are found, we throw an exception with a descriptive error message.</p>
</li>
</ul>
<p>Now Your Service class should look like this:</p>
<pre><code class="lang-csharp">


<span class="hljs-keyword">using</span> AutoMapper;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> TodoAPI.AppDataContext;
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Interface;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoServices</span> : <span class="hljs-title">ITodoServices</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TodoDbContext _context;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;TodoServices&gt; _logger;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMapper _mapper;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoServices</span>(<span class="hljs-params">TodoDbContext context, ILogger&lt;TodoServices&gt; logger, IMapper mapper</span>)</span>
        {
            _context = context;
            _logger = logger;
            _mapper = mapper;
        }




        <span class="hljs-comment">//  Create Todo for it be save in the datbase </span>

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> todo = _mapper.Map&lt;Todo&gt;(request);
                todo.CreatedAt = DateTime.Now;
                _context.Todos.Add(todo);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(ex, <span class="hljs-string">"An error occurred while creating the todo item."</span>);
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"An error occurred while creating the todo item."</span>);
            }
        }

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;Todo&gt;&gt; GetAllAsync()
        {
            <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.ToListAsync();
            <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">" No Todo items found"</span>);
            }
            <span class="hljs-keyword">return</span> todo;

        }
        <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-comment">// Get all TODO Items from the database </span>


        <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;Todo&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> Task <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotImplementedException();
        }
    }
}
</code></pre>
<p>Now we have implemented the <code>CreateTodoAsync</code> and <code>GetAllAsync</code> methods in the <code>TodoServices</code> class. Before we proceed to implement the remaining methods, let's create routes for our API in the Controllers folder. So now let's create the TodoController class.</p>
<h2 id="step-11"> Step 11: Create the TodoController Class  </h2>

<p>In ASP.NET Core, controllers are responsible for handling incoming HTTP requests and sending responses. They serve as the entry point for our API, defining the routes and actions that clients can interact with.</p>
<p>Let's create a new file named <code>TodoController.cs</code> in the <code>Controllers</code> folder and add the following code:</p>
<pre><code class="lang-csharp">

<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> TodoAPI.Interface;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITodoServices _todoServices;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoController</span>(<span class="hljs-params">ITodoServices todoServices</span>)</span>
        {
            _todoServices = todoServices;
        }

    }
}
</code></pre>
<p>The <code>TodoController</code> class inherits from <code>ControllerBase</code>, a base class provided by ASP.NET Core for creating controllers. We've also added a route prefix of <code>api/[controller]</code> to the controller, which will be used as the base route for all actions in the controller.</p>
<h2 id="step-12"> Step 12: Implement the CreateTodoAsync  Method in the TodoController Class  </h2>

<p>Now that we have our Controller class, let's implement the <code>CreateTodoAsync</code> method in the <code>TodoController</code> class. This method will handle the creation of new Todo items in our database.</p>
<p>Navigate to the <code>TodoController</code> class and add the following code to the <code>CreateTodoAsync</code> method:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Controllers/TodoController.cs</span>

<span class="hljs-comment">// ...</span>
  [<span class="hljs-meta">HttpPost</span>]
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
  {
      <span class="hljs-keyword">if</span> (!ModelState.IsValid)
      {
          <span class="hljs-keyword">return</span> BadRequest(ModelState);
      }


      <span class="hljs-keyword">try</span>
      {

          <span class="hljs-keyword">await</span> _todoServices.CreateTodoAsync(request);
          <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Blog post successfully created"</span> });

      }
      <span class="hljs-keyword">catch</span> (Exception ex)
      {
          <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while creating the  crating Todo Item"</span>, error = ex.Message });

      }
  }
  <span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>CreateTodoAsync</code> method:</p>
<ul>
<li><p><strong>Model Validation</strong>: We check if the request model is valid using <code>ModelState.IsValid</code>. If the model is not valid, we return a <code>BadRequest</code> response with the model state errors.</p>
</li>
<li><p><strong>Creating a Todo Item</strong>: We call the <code>CreateTodoAsync</code> method from the <code>ITodoServices</code> interface to create a new Todo item in the database.</p>
</li>
<li><p><strong>Success Response</strong>: If the Todo item is created successfully, we return an <code>Ok</code> response with a success message.</p>
</li>
<li><p><strong>Error Handling</strong>: If an error occurs during the creation process, we return a <code>500 Internal Server Error</code> response with an error message.</p>
</li>
</ul>
<p>Now let's implement the <code>GetAllAsync</code> method in the <code>TodoController</code> class. This method will retrieve all Todo items from the database.</p>
<p>Navigate to the <code>TodoController</code> class and add the following code to the <code>GetAllAsync</code> method:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Controllers/TodoController.cs </span>

<span class="hljs-comment">// ...</span>

  [<span class="hljs-meta">HttpGet</span>]
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetAllAsync</span>(<span class="hljs-params"></span>)</span>
  {
      <span class="hljs-keyword">try</span>
      {
          <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetAllAsync();
          <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span> || !todo.Any())
          {
              <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"No Todo Items  found"</span> });
          }
          <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Successfully retrieved all blog posts"</span>, data = todo });

      }
      <span class="hljs-keyword">catch</span> (Exception ex)
      {
          <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while retrieving all Tood it posts"</span>, error = ex.Message });


      }
  }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>GetAllAsync</code> method:</p>
<ul>
<li><p><strong>Retrieving Todo Items</strong>: We call the <code>GetAllAsync</code> method from the <code>ITodoServices</code> interface to fetch all Todo items from the database.</p>
</li>
<li><p><strong>Success Response</strong>: If Todo items are retrieved successfully, we return an <code>Ok</code> response with a success message and the list of Todo items.</p>
</li>
<li><p><strong>Error Handling</strong>: If an error occurs during the retrieval process, we return a <code>500 Internal Server Error</code> response with an error message.</p>
</li>
</ul>
<p>Now your <code>TodoController</code> class should look like this:</p>
<pre><code class="lang-csharp">


<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Interface;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITodoServices _todoServices;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoController</span>(<span class="hljs-params">ITodoServices todoServices</span>)</span>
        {
            _todoServices = todoServices;
        }



<span class="hljs-comment">// Creating new Todo Item</span>
[<span class="hljs-meta">HttpPost</span>]
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
  {
      <span class="hljs-keyword">if</span> (!ModelState.IsValid)
      {
          <span class="hljs-keyword">return</span> BadRequest(ModelState);
      }


      <span class="hljs-keyword">try</span>
      {

          <span class="hljs-keyword">await</span> _todoServices.CreateTodoAsync(request);
          <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Blog post successfully created"</span> });

      }
      <span class="hljs-keyword">catch</span> (Exception ex)
      {
          <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while creating the  crating Todo Item"</span>, error = ex.Message });

      }
  }

    <span class="hljs-comment">// Get all Todo Items</span>

      [<span class="hljs-meta">HttpGet</span>]
  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetAllAsync</span>(<span class="hljs-params"></span>)</span>
  {
      <span class="hljs-keyword">try</span>
      {
          <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetAllAsync();
          <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span> || !todo.Any())
          {
              <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"No Todo Items  found"</span> });
          }
          <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Successfully retrieved all blog posts"</span>, data = todo });

      }
      <span class="hljs-keyword">catch</span> (Exception ex)
      {
          <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while retrieving all Tood it posts"</span>, error = ex.Message });


      }
  }

    }
}
</code></pre>
<p>At this point, we've implemented the <code>CreateTodoAsync</code> and <code>GetAllAsync</code> methods in the <code>TodoController</code> class. These methods allow us to create new Todo items and retrieve all Todo items from the database. Let's try to run the application and see if everything is working fine.</p>
<p>Run the application by running the following command:</p>
<pre><code class="lang-bash">

dotnet run
</code></pre>
<p>If you see the following output, it means your application is running successfully:</p>
<pre><code class="lang-bash">
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5086
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: E:\Todo\TodoAPI4
</code></pre>
<p>While we'll be using Postman within Visual Studio Code for making API requests, it's worth noting that .NET 8 includes a built-in Swagger UI. This feature allows us to interact with our API endpoints directly from a web browser. To access the Swagger UI, open your browser and navigate to <code>https://localhost:5086/swagger/index.html</code>. You should see a page similar to the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/SwaggerUI.png" alt="SwaggerUI" width="600" height="400" loading="lazy">
This indicates that we've made significant progress. We've created an API that can create and retrieve Todo items. Let's test this by attempting to create a new Todo item using our API.</p>
<p>Open Postman and create a new POST request with the following URL: <code>https://localhost:5086/api/todo</code>. Set the request body to the following JSON object:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn ASP.NET Core"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with ASP.NET Core"</span>,
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">5</span>
}
</code></pre>
<p>Upon executing this request, you may encounter an error. This is because we haven't yet added our connection string to the <code>appsettings.json</code> file. Let's rectify this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanError.png" alt="PostmanError" width="600" height="400" loading="lazy"></p>
<p><strong>Note</strong>: The error above is due to the absence of a connection string in the <code>appsettings.json</code> file. Let's add the connection string to the <code>appsettings.json</code> file.</p>
<p>Before we do that, let's setup or SQL Server Database. First Open your SQL Server Management Studio and you should see the below screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/SQLServerManagementStudio.png" alt="SQLServerManagementStudio" width="600" height="400" loading="lazy"></p>
<p>To connect to the SQL Server, where is says <code>Server Name</code> you can type <code>localhost</code> or <code>.</code> and click on the <code>Connect</code> button.</p>
<p>After connecting to the SQL Server, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/SQLServerManagementStudio2.png" alt="SQLServerManagementStudio2" width="600" height="400" loading="lazy"></p>
<p>Now go to your <code>appsettings.json</code> file and add the following connection string:</p>
<pre><code class="lang-json">
<span class="hljs-comment">//appsettings.json</span>
{
  <span class="hljs-attr">"DbSettings"</span>: {
    <span class="hljs-attr">"ConnectionString"</span>: <span class="hljs-string">"Server=localhost;Database=TodoAPIDb;  Integrated Security=true;  TrustServerCertificate=true;"</span>
  },
  <span class="hljs-attr">"Logging"</span>: {
    <span class="hljs-attr">"LogLevel"</span>: {
      <span class="hljs-attr">"Default"</span>: <span class="hljs-string">"Information"</span>,
      <span class="hljs-attr">"Microsoft"</span>: <span class="hljs-string">"Warning"</span>,
      <span class="hljs-attr">"Microsoft.Hosting.Lifetime"</span>: <span class="hljs-string">"Information"</span>
    },
    <span class="hljs-attr">"AllowedHosts"</span>: <span class="hljs-string">"*"</span>
  }
}
</code></pre>
<p>Let me explain the connection string above:</p>
<ul>
<li><code>Server</code>: This is the server name where the database is hosted. In this case, we're using <code>localhost</code> to connect to the local SQL Server instance.</li>
<li><code>Database</code>: This is the name of the database we want to connect to. We've set it to <code>TodoAPIDb</code>.</li>
<li><code>Integrated Security</code>: This parameter specifies that we're using Windows authentication to connect to the database.</li>
<li><code>TrustServerCertificate</code>: This parameter specifies that we trust the server certificate when connecting to the database.</li>
</ul>
<p>Now we need to register our <code>Service</code> and <code>Iservices</code> in the <code>Program.cs</code> file.</p>
<p>Add the service to the <code>Program.cs</code> file:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Program.cs</span>

<span class="hljs-comment">// ...</span>

builder.Services.AddScoped&lt;ITodoServices, TodoServices&gt;();

<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="step-13"> Step 13: Implement Migrations and Update the Database  </h2>

<p>Migrations in Entity Framework Core provide a mechanism to keep the database schema in sync with the application's data model. They generate SQL scripts that can be applied to the database to reflect changes in the data model, eliminating the need for manual database schema updates.</p>
<p>To create a migration, ensure you're in the root directory of your project and run the following command in the terminal:</p>
<pre><code class="lang-bash">dotnet ef migrations add InitialCreate
</code></pre>
<p>Upon successful execution, you'll see an output similar to the following:</p>
<pre><code class="lang-bash">dotnet ef migrations add InitialCreate
Build started...
Build succeeded.
Done. To undo this action, use <span class="hljs-string">'ef migrations remove'</span>
</code></pre>
<p>This command generates a new migration named <code>InitialCreate</code>, which contains SQL scripts derived from the changes in our data model. A new folder named <code>Migrations</code> will appear in your project directory.</p>
<p>To apply the migration and update the database, execute the following command:</p>
<pre><code class="lang-bash">dotnet ef database update
</code></pre>
<p>You might encounter an error like this:</p>
<pre><code class="lang-bash">  at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.&lt;&gt;c__DisplayClass0_0.&lt;.ctor&gt;b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Only the invariant culture is supported <span class="hljs-keyword">in</span> globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode <span class="hljs-keyword">for</span> more information. (Parameter <span class="hljs-string">'name'</span>)
en-us is an invalid culture identifier.
</code></pre>
<p>This error indicates that the <code>en-us</code> culture is not supported in globalization-invariant mode. To resolve this, open the <code>TodoAPI.csproj</code> file and change <code>&lt;InvariantGlobalization&gt;true&lt;/InvariantGlobalization&gt;</code> to <code>&lt;InvariantGlobalization&gt;false&lt;/InvariantGlobalization&gt;</code>.</p>
<p>After making this change, run the <code>dotnet ef database update</code> command again. If the migration is successful, you'll see an output similar to the following:</p>
<pre><code class="lang-bash">
Build started...
Build succeeded.
Applying migration <span class="hljs-string">'20240518180222_InitialCreate'</span>.
Done.
</code></pre>
<p>This indicates that the migration has been applied successfully, and the database has been updated with the necessary schema changes.</p>
<p>Congratulations! You've successfully created a migration and updated the database schema. Now, let's test our API by creating a new Todo item using Postman.</p>
<h2 id="step-14">  Step 14: Verify Your API with Postman  </h2>

<p>Before we can interact with our API, we need to ensure that our application is up and running. Start the application by executing the following command in the terminal:</p>
<pre><code class="lang-bash">dotnet run
</code></pre>
<p>With the application running, we can now use Postman to send requests to our API. Let's create a new Todo item:</p>
<ol>
<li>Open Postman and create a new request.</li>
<li>Set the request method to <code>POST</code>.</li>
<li>Enter the following URL: <code>https://localhost:5086/api/todo</code>.</li>
<li>In the <code>Headers</code> tab, set the <code>Content-Type</code> to <code>application/json</code>.</li>
<li>In the <code>Body</code> tab, select <code>raw</code> and enter the following JSON object:</li>
</ol>
<pre><code class="lang-json">{
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn ASP.NET Core"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with ASP.NET Core"</span>,
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">5</span>
}
</code></pre>
<ol start="6">
<li>Click on the <code>Send</code> button to execute the request.</li>
</ol>
<p>If the request is successful, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Todo item successfully created"</span>
}
</code></pre>
<p>The image below illustrates the successful creation of a new Todo item using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanSuccess.png" alt="PostmanSuccess" width="600" height="400" loading="lazy"></p>
<p>Now that we've successfully created a new Todo item, let's retrieve all Todo items from the database using our API.</p>
<h2 id="step-15">   Step 15: Retrieve All Todo Items  </h2>

<p>To retrieve all Todo items from the database, follow these steps:</p>
<ol>
<li><p>Open Postman and create a new request.</p>
</li>
<li><p>Set the request method to <code>GET</code>. </p>
</li>
<li><p>Enter the following URL: <code>https://localhost:5086/api/todo</code>.</p>
</li>
<li><p>Click on the <code>Send</code> button to execute the request.</p>
</li>
</ol>
<p>If the request is successful, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">
   {
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Successfully retrieved all blog posts"</span>,
    <span class="hljs-attr">"data"</span>: [
        {
            <span class="hljs-attr">"id"</span>: <span class="hljs-string">"e9898d1b-9ad3-4482-ad65-08dc77664fab"</span>,
            <span class="hljs-attr">"title"</span>: <span class="hljs-string">"string"</span>,
            <span class="hljs-attr">"description"</span>: <span class="hljs-string">"string"</span>,
            <span class="hljs-attr">"isComplete"</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2024-05-18T16:52:22.054Z"</span>,
            <span class="hljs-attr">"priority"</span>: <span class="hljs-number">5</span>,
            <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-05-18T18:14:08.1755565+00:00"</span>,
            <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"0001-01-01T00:00:00"</span>
        }
    ]
}
</code></pre>
<p>The image below illustrates the successful retrieval of all Todo items using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanGetAll.png" alt="PostmanGetAll" width="600" height="400" loading="lazy"></p>
<p>Congratulations! You've successfully created an API that can create and retrieve Todo items. This marks the completion of our Todo API project. You've learned how to set up a .NET Core project, define models, create a database context, implement a service layer, and create API endpoints. You've also learned how to use Postman to interact with your API and test its functionality.</p>
<p>Now let's move on to create the <code>GetByIdAsync</code>, <code>UpdateTodoAsync</code>, and <code>DeleteTodoAsync</code> methods in the <code>TodoServices</code> class and <code>TodoController</code> class.</p>
<h2 id="step-16">  Step 16: Implement the GetByIdAsync Method  </h2>

<p>The <code>GetByIdAsync</code> method retrieves a specific Todo item by its <code>Id</code>. We'll implement this method in both the <code>TodoServices</code> and <code>TodoController</code> classes.</p>
<h3 id="heading-the-todoservices-class">  The <code>TodoServices</code> Class  </h3>


<p>In the <code>TodoServices</code> class, add the following code to the <code>GetByIdAsync</code> method:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;Todo&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
{
    <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
    <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
    {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> KeyNotFoundException(<span class="hljs-string">$"No Todo item with Id <span class="hljs-subst">{id}</span> found."</span>);
    }
    <span class="hljs-keyword">return</span> todo;
}
</code></pre>
<p>This method uses Entity Framework Core's <code>FindAsync</code> method to fetch a Todo item by its <code>Id</code>. If no Todo item is found, it throws a <code>KeyNotFoundException</code> with a descriptive error message.</p>
<h3 id="heading-the-todocontroller-class">   The <code>TodoController</code> Class  </h3>


<p>In the <code>TodoController</code> class, add the following code to the <code>GetByIdAsync</code> method:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Controllers/TodoController.cs</span>

[<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
{
    <span class="hljs-keyword">try</span>
    {
        <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetByIdAsync(id);
        <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
        {
            <span class="hljs-keyword">return</span> NotFound(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"No Todo item with Id <span class="hljs-subst">{id}</span> found."</span> });
        }
        <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Successfully retrieved Todo item with Id <span class="hljs-subst">{id}</span>."</span>, data = todo });
    }
    <span class="hljs-keyword">catch</span> (Exception ex)
    {
        <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while retrieving the Todo item with Id <span class="hljs-subst">{id}</span>."</span>, error = ex.Message });
    }
}
</code></pre>
<p>This method calls the <code>GetByIdAsync</code> method from the <code>ITodoServices</code> interface to fetch a Todo item by its <code>Id</code>. If a Todo item is retrieved successfully, it returns an <code>Ok</code> response with a success message and the Todo item. If an error occurs during the retrieval process, it returns a <code>500 Internal Server Error</code> response with an error message.</p>
<h2 id="step-17">  Step 17: Implement the UpdateTodoAsync Method   </h2>

<p>The <code>UpdateTodoAsync</code> method in the <code>TodoServices</code> class modifies an existing Todo item in the database. Let's implement this method now.</p>
<p>Navigate to the <code>TodoServices</code> class and add the following code to the <code>UpdateTodoAsync</code> method:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
 {
     <span class="hljs-keyword">try</span>
     {
         <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
         <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
         {
             <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$"Todo item with id <span class="hljs-subst">{id}</span> not found."</span>);
         }

         <span class="hljs-keyword">if</span> (request.Title != <span class="hljs-literal">null</span>)
         {
             todo.Title = request.Title;
         }

         <span class="hljs-keyword">if</span> (request.Description != <span class="hljs-literal">null</span>)
         {
             todo.Description = request.Description;
         }

         <span class="hljs-keyword">if</span> (request.IsComplete != <span class="hljs-literal">null</span>)
         {
             todo.IsComplete = request.IsComplete.Value;
         }

         <span class="hljs-keyword">if</span> (request.DueDate != <span class="hljs-literal">null</span>)
         {
             todo.DueDate = request.DueDate.Value;
         }

         <span class="hljs-keyword">if</span> (request.Priority != <span class="hljs-literal">null</span>)
         {
             todo.Priority = request.Priority.Value;
         }

         todo.UpdatedAt = DateTime.Now;

         <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
     }
     <span class="hljs-keyword">catch</span> (Exception ex)
     {
         _logger.LogError(ex, <span class="hljs-string">$"An error occurred while updating the todo item with id <span class="hljs-subst">{id}</span>."</span>);
         <span class="hljs-keyword">throw</span>;
     }
 }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>UpdateTodoAsync</code> method:</p>
<ul>
<li><p><strong>Retrieving a Specific Todo Item</strong>: We use Entity Framework Core's <code>FindAsync</code> method to fetch a Todo item by its <code>Id</code>.</p>
</li>
<li><p><strong>Updating the Todo Item</strong>: We update the Todo item properties based on the values provided in the <code>UpdateTodoRequest</code> object.</p>
</li>
<li><p><strong>Error Handling</strong>: If no Todo item is found with the specified <code>Id</code>, we throw an exception with a descriptive error message.</p>
</li>
</ul>
<p>Now let's implement the <code>UpdateTodoAsync</code> method in the <code>TodoController</code> class. This method will modify an existing Todo item in the database.</p>
<p>Navigate to the <code>TodoController</code> class and add the following code to the <code>UpdateTodoAsync</code> method:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Controllers/TodoController.cs</span>

<span class="hljs-comment">// ... </span>
   [<span class="hljs-meta">HttpPut(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
   {

       <span class="hljs-keyword">if</span> (!ModelState.IsValid)
       {
           <span class="hljs-keyword">return</span> BadRequest(ModelState);
       }

       <span class="hljs-keyword">try</span>
       {

           <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetByIdAsync(id);
           <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
           {
               <span class="hljs-keyword">return</span> NotFound(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Todo Item  with id <span class="hljs-subst">{id}</span> not found"</span> });
           }

           <span class="hljs-keyword">await</span> _todoServices.UpdateTodoAsync(id, request);
           <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$" Todo Item  with id <span class="hljs-subst">{id}</span> successfully updated"</span> });

       }
       <span class="hljs-keyword">catch</span> (Exception ex)
       {
           <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while updating blog post with id <span class="hljs-subst">{id}</span>"</span>, error = ex.Message });


       }


   }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>UpdateTodoAsync</code> method:</p>
<ul>
<li><p><strong>Model Validation</strong>: We check if the request model is valid using <code>ModelState.IsValid</code>. If the model is not valid, we return a <code>BadRequest</code> response with the model state errors.</p>
</li>
<li><p><strong>Retrieving a Specific Todo Item</strong>: We call the <code>GetByIdAsync</code> method from the <code>ITodoServices</code> interface to fetch a Todo item by its <code>Id</code>.</p>
</li>
<li><p><strong>Updating the Todo Item</strong>: If the Todo item is found, we call the <code>UpdateTodoAsync</code> method from the <code>ITodoServices</code> interface to update the Todo item.</p>
</li>
<li><p><strong>Success Response</strong>: If the Todo item is updated successfully, we return an <code>Ok</code> response with a success message.</p>
</li>
<li><p><strong>Error Handling</strong>: If an error occurs during the update process, we return a <code>500 Internal Server Error</code> response with an error message.</p>
</li>
</ul>
<h2 id="step-18"> Step 18: Implement the DeleteTodoAsync Method   </h2>

<p>The <code>DeleteTodoAsync</code> method in the <code>TodoServices</code> class removes a Todo item from the database. Let's implement this method now.</p>
<p>Navigate to the <code>TodoServices</code> class and add the following code to the <code>DeleteTodoAsync</code> method:</p>
<pre><code class="lang-csharp">

<span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-comment">// ...</span>


 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
 {

     <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
     <span class="hljs-keyword">if</span>(todo != <span class="hljs-literal">null</span>)
     {
          _context.Todos.Remove(todo);
         <span class="hljs-keyword">await</span> _context.SaveChangesAsync();

     }
     <span class="hljs-keyword">else</span>
     {
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$"No  item found with the id <span class="hljs-subst">{id}</span>"</span>);
     }


 }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>DeleteTodoAsync</code> method:</p>
<ul>
<li><p><strong>Retrieving a Specific Todo Item</strong>: We use Entity Framework Core's <code>FindAsync</code> method to fetch a Todo item by its <code>Id</code>.</p>
</li>
<li><p><strong>Removing the Todo Item</strong>: If the Todo item is found, we remove it from the <code>Todos</code> DbSet in our context and save the changes asynchronously.</p>
</li>
<li><p><strong>Error Handling</strong>: If no Todo item is found with the specified <code>Id</code>, we throw an exception with a descriptive error message.</p>
</li>
</ul>
<p>Now let's implement the <code>DeleteTodoAsync</code> method in the <code>TodoController</code> class. This method will remove a Todo item from the database.</p>
<p>Navigate to the <code>TodoController</code> class and add the following code to the <code>DeleteTodoAsync</code> method:</p>
<pre><code class="lang-csharp">
<span class="hljs-comment">// Controllers/TodoController.cs</span>

<span class="hljs-comment">// ...</span>

 [<span class="hljs-meta">HttpDelete(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
 {
     <span class="hljs-keyword">try</span>
     {
         <span class="hljs-keyword">await</span> _todoServices.DeleteTodoAsync(id);
         <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Todo  with id <span class="hljs-subst">{id}</span> successfully deleted"</span> });

     }
     <span class="hljs-keyword">catch</span> (Exception ex)
     {
         <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while deleting Todo Item  with id <span class="hljs-subst">{id}</span>"</span>, error = ex.Message });

     }
 }



<span class="hljs-comment">// ...</span>
</code></pre>
<p>Here's a breakdown of the <code>DeleteTodoAsync</code> method:</p>
<ul>
<li><p><strong>Removing the Todo Item</strong>: We call the <code>DeleteTodoAsync</code> method from the <code>ITodoServices</code> interface to remove a Todo item by its <code>Id</code>.</p>
</li>
<li><p><strong>Success Response</strong>: If the Todo item is deleted successfully, we return an <code>Ok</code> response with a success message.</p>
</li>
<li><p><strong>Error Handling</strong>: If an error occurs during the deletion process, we return a <code>500 Internal Server Error</code> response with an error message.</p>
</li>
</ul>
<p>Now your <code>TodoServices</code> class should look like this:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Services/TodoServices.cs</span>

<span class="hljs-keyword">using</span> AutoMapper;
<span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> TodoAPI.AppDataContext;
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Interface;
<span class="hljs-keyword">using</span> TodoAPI.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoServices</span> : <span class="hljs-title">ITodoServices</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> TodoDbContext _context;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;TodoServices&gt; _logger;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMapper _mapper;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoServices</span>(<span class="hljs-params">TodoDbContext context, ILogger&lt;TodoServices&gt; logger, IMapper mapper</span>)</span>
        {
            _context = context;
            _logger = logger;
            _mapper = mapper;
        }




        <span class="hljs-comment">//  Create Todo for it to be saved in the datbase </span>

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> todo = _mapper.Map&lt;Todo&gt;(request);
                todo.CreatedAt = DateTime.Now;
                _context.Todos.Add(todo);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(ex, <span class="hljs-string">"An error occurred while creating the todo item."</span>);
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"An error occurred while creating the todo item."</span>);
            }
        }


        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;Todo&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
            <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$" No Items with <span class="hljs-subst">{id}</span> found "</span>);
            }
            <span class="hljs-keyword">return</span> todo;
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
                <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
                {
                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$"Todo item with id <span class="hljs-subst">{id}</span> not found."</span>);
                }

                <span class="hljs-keyword">if</span> (request.Title != <span class="hljs-literal">null</span>)
                {
                    todo.Title = request.Title;
                }

                <span class="hljs-keyword">if</span> (request.Description != <span class="hljs-literal">null</span>)
                {
                    todo.Description = request.Description;
                }

                <span class="hljs-keyword">if</span> (request.IsComplete != <span class="hljs-literal">null</span>)
                {
                    todo.IsComplete = request.IsComplete.Value;
                }

                <span class="hljs-keyword">if</span> (request.DueDate != <span class="hljs-literal">null</span>)
                {
                    todo.DueDate = request.DueDate.Value;
                }

                <span class="hljs-keyword">if</span> (request.Priority != <span class="hljs-literal">null</span>)
                {
                    todo.Priority = request.Priority.Value;
                }

                todo.UpdatedAt = DateTime.Now;

                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                _logger.LogError(ex, <span class="hljs-string">$"An error occurred while updating the todo item with id <span class="hljs-subst">{id}</span>."</span>);
                <span class="hljs-keyword">throw</span>;
            }
        }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;Todo&gt;&gt; GetAllAsync()
        {
            <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.ToListAsync();
            <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">" No Todo items found"</span>);
            }
            <span class="hljs-keyword">return</span> todo;

        }
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {

            <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _context.Todos.FindAsync(id);
            <span class="hljs-keyword">if</span> (todo != <span class="hljs-literal">null</span>)
            {
                _context.Todos.Remove(todo);
                <span class="hljs-keyword">await</span> _context.SaveChangesAsync();

            }
            <span class="hljs-keyword">else</span>
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">$"No  item found with the id <span class="hljs-subst">{id}</span>"</span>);
            }


        }




    }
}
</code></pre>
<p>Now your <code>TodoController</code> class should look like this:</p>
<pre><code class="lang-csharp">
<span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> TodoAPI.Contracts;
<span class="hljs-keyword">using</span> TodoAPI.Interface;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">TodoAPI.Controllers</span>
{
    [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TodoController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITodoServices _todoServices;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TodoController</span>(<span class="hljs-params">ITodoServices todoServices</span>)</span>
        {
            _todoServices = todoServices;
        }



        <span class="hljs-comment">// Creating new Todo Item</span>
        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">CreateTodoAsync</span>(<span class="hljs-params">CreateTodoRequest request</span>)</span>
        {
            <span class="hljs-keyword">if</span> (!ModelState.IsValid)
            {
                <span class="hljs-keyword">return</span> BadRequest(ModelState);
            }


            <span class="hljs-keyword">try</span>
            {

                <span class="hljs-keyword">await</span> _todoServices.CreateTodoAsync(request);
                <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Blog post successfully created"</span> });

            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while creating the  crating Todo Item"</span>, error = ex.Message });

            }
        }

        <span class="hljs-comment">// Get all Todo Items</span>

        [<span class="hljs-meta">HttpGet</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetAllAsync</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetAllAsync();
                <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span> || !todo.Any())
                {
                    <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"No Todo Items  found"</span> });
                }
                <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">"Successfully retrieved all blog posts"</span>, data = todo });

            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">"An error occurred while retrieving all Tood it posts"</span>, error = ex.Message });


            }
        }

        [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">GetByIdAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {

                <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetByIdAsync(id);
                <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
                {
                    <span class="hljs-keyword">return</span> NotFound(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Now Todo item with id <span class="hljs-subst">{id}</span> not found"</span> });

                }
                <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Successfully retrieved  todo item with id <span class="hljs-subst">{id}</span>"</span>, data = todo });

            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while retrieving   todo item  with id <span class="hljs-subst">{id}</span>"</span>, error = ex.Message });

            }
        }



        [<span class="hljs-meta">HttpPut(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">UpdateTodoAsync</span>(<span class="hljs-params">Guid id, UpdateTodoRequest request</span>)</span>
        {

            <span class="hljs-keyword">if</span> (!ModelState.IsValid)
            {
                <span class="hljs-keyword">return</span> BadRequest(ModelState);
            }

            <span class="hljs-keyword">try</span>
            {

                <span class="hljs-keyword">var</span> todo = <span class="hljs-keyword">await</span> _todoServices.GetByIdAsync(id);
                <span class="hljs-keyword">if</span> (todo == <span class="hljs-literal">null</span>)
                {
                    <span class="hljs-keyword">return</span> NotFound(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Todo Item  with id <span class="hljs-subst">{id}</span> not found"</span> });
                }

                <span class="hljs-keyword">await</span> _todoServices.UpdateTodoAsync(id, request);
                <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$" Todo Item  with id <span class="hljs-subst">{id}</span> successfully updated"</span> });

            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while updating blog post with id <span class="hljs-subst">{id}</span>"</span>, error = ex.Message });


            }


        }


        [<span class="hljs-meta">HttpDelete(<span class="hljs-meta-string">"{id:guid}"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">DeleteTodoAsync</span>(<span class="hljs-params">Guid id</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">await</span> _todoServices.DeleteTodoAsync(id);
                <span class="hljs-keyword">return</span> Ok(<span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"Todo  with id <span class="hljs-subst">{id}</span> successfully deleted"</span> });

            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                <span class="hljs-keyword">return</span> StatusCode(<span class="hljs-number">500</span>, <span class="hljs-keyword">new</span> { message = <span class="hljs-string">$"An error occurred while deleting Todo Item  with id <span class="hljs-subst">{id}</span>"</span>, error = ex.Message });

            }
        }


    }
}
</code></pre>
<p>Now that we've implemented the <code>GetByIdAsync</code>, <code>UpdateTodoAsync</code>, and <code>DeleteTodoAsync</code> methods in the <code>TodoServices</code> and <code>TodoController</code> classes, we can test our API to ensure that everything is working as expected.</p>
<h2 id="step-19"> Step 19: Test Your API Endpoints with Postman   </h2>

<p>With our application up and running, we can now test all our API endpoints. We'll create new Todo items, retrieve all Todo items, fetch a specific Todo item by its <code>Id</code>, update a Todo item, and delete a Todo item using Postman. Let's start by creating three new Todo items.</p>
<p>Note that we'll be creating these Todo items one at a time, not all at once. Follow these steps for each Todo item:</p>
<ol>
<li>Open Postman and create a new request.</li>
<li>Set the request method to <code>POST</code>.</li>
<li>Enter the following URL: <code>http://localhost:5086/api/todo</code>.</li>
<li>In the <code>Headers</code> tab, set the <code>Content-Type</code> to <code>application/json</code>.</li>
<li>In the <code>Body</code> tab, select <code>raw</code> and enter one of the following JSON objects:</li>
</ol>
<p>For the first Todo item:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn ASP.NET Core"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with ASP.NET Core"</span>,
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">2</span>
}
</code></pre>
<p>For the second Todo item:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn C#"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with C#"</span>,
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">3</span>
}
</code></pre>
<p>For the third Todo item:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn SQL"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with SQL"</span>,
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">1</span>
}
</code></pre>
<ol start="6">
<li>Click on the <code>Send</code> button to execute the request for each Todo item.</li>
</ol>
<p>If each request is successful, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Todo item successfully created"</span>
}
</code></pre>
<p>This indicates that the Todo item has been successfully created. Repeat the steps for each Todo item.</p>
<h3 id="heading-how-to-retrieve-all-todo-items"> How to Retrieve All Todo Items   </h3>

<p>To fetch all Todo items from the database, follow these steps:</p>
<ol>
<li>Launch Postman and initiate a new request.</li>
<li>Set the HTTP method to <code>GET</code>.</li>
<li>Input the following URL: <code>http://localhost:5086/api/todo</code>.</li>
<li>Click the <code>Send</code> button to execute the request.</li>
</ol>
<p>The image below demonstrates a successful retrieval of all Todo items using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanGetAll-1.png" alt="PostmanGetAll-1" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-fetch-a-specific-todo-item-by-id">  How to Fetch a Specific Todo Item by Id  </h3>

<p>To retrieve a specific Todo item using its <code>Id</code>, follow these steps:</p>
<ol>
<li>Launch Postman and initiate a new request.</li>
<li>Set the HTTP method to <code>GET</code>.</li>
<li>Input the following URL: <code>http://localhost:5086/api/todo/{id}</code>, replacing <code>{id}</code> with the <code>Id</code> of the Todo item you wish to retrieve. For example, <code>http://localhost:5086/api/todo/e9898d1b-9ad3-4482-ad65-08dc77664fab</code>.</li>
<li>Click the <code>Send</code> button to execute the request.</li>
</ol>
<p>Upon successful execution, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Successfully retrieved  todo item with id e9898d1b-9ad3-4482-ad65-08dc77664fab"</span>,
    <span class="hljs-attr">"data"</span>: {
        <span class="hljs-attr">"id"</span>: <span class="hljs-string">"e9898d1b-9ad3-4482-ad65-08dc77664fab"</span>,
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">"description"</span>: <span class="hljs-string">"string"</span>,
        <span class="hljs-attr">"isComplete"</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2024-05-18T16:52:22.054"</span>,
        <span class="hljs-attr">"priority"</span>: <span class="hljs-number">5</span>,
        <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-05-18T18:14:08.1755565"</span>,
        <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"0001-01-01T00:00:00"</span>
    }
}
</code></pre>
<p>The image below demonstrates the successful retrieval of a specific Todo item using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanGetById.png" alt="PostmanGetById" width="600" height="400" loading="lazy">)</p>
<h3 id="heading-how-to-update-a-todo-item">   How to Update a Todo Item </h3>


<p>In our Todo model, we have a property <code>isComplete</code> which is initially set to <code>false</code> when a Todo item is created. This property is used to indicate whether a task has been completed or not. To mark a task as complete, we need to update this property to <code>true</code>. Note that we can only update one Todo item at a time, and we identify the item to update by its <code>Id</code>.</p>
<p>Let's fetch all the Todo items, select one and update it by setting the <code>isComplete</code> property to <code>true</code>.</p>
<p>Follow these steps to update a Todo item:</p>
<ol>
<li>Launch Postman and initiate a new request.</li>
<li>Set the HTTP method to <code>PUT</code>.</li>
<li>Input the following URL: <code>http://localhost:5086/api/todo/{id}</code>, replacing <code>{id}</code> with the <code>Id</code> of the Todo item you wish to update. For example, <code>http://localhost:5086/api/todo/e9898d1b-9ad3-4482-ad65-08dc77664fab</code>.</li>
<li>In the <code>Headers</code> tab, set the <code>Content-Type</code> to <code>application/json</code>.</li>
<li>In the <code>Body</code> tab, select <code>raw</code> and enter the following JSON object:</li>
</ol>
<pre><code class="lang-json">{
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"21ebe2c2-79c0-45d4-4139-08dc789e3eb2"</span>,
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Learn C#"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Learn how to build web applications with C#"</span>,
    <span class="hljs-attr">"isComplete"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Set the isComplete to true</span>
    <span class="hljs-attr">"dueDate"</span>: <span class="hljs-string">"2022-12-31T00:00:00"</span>,
    <span class="hljs-attr">"priority"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-05-20T07:27:39.3730049+00:00"</span>,
    <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-string">"0001-01-01T00:00:00"</span>
}
</code></pre>
<ol start="6">
<li>Click the <code>Send</code> button to execute the request.</li>
</ol>
<p>Upon successful execution, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Todo Item with id 21ebe2c2-79c0-45d4-4139-08dc789e3eb2 successfully updated"</span>
}
</code></pre>
<p>The image below demonstrates the successful update of a Todo item using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanUpdate.png" alt="PostmanUpdate" width="600" height="400" loading="lazy"></p>
<p><strong>Note</strong>: The <code>isComplete</code> property of the Todo item has been updated to <code>true</code>. Now, when you fetch all Todo items from the database, you will see the <code>isComplete</code> property is <code>true</code> for the updated Todo item.</p>
<p>Now let's see how to delete a Todo item from the database.</p>
<h3 id="heading-how-to-delete-a-todo-item">  How to Delete a Todo Item </h3>


<p>To remove a Todo item from the database, follow these steps: </p>
<ol>
<li>Open Postman and create a new request.</li>
<li>Set the HTTP method to <code>DELETE</code>.</li>
<li>Enter the following URL: <code>http://localhost:5086/api/todo/{id}</code>, replacing <code>{id}</code> with the <code>Id</code> of the Todo item you intend to remove. For instance, <code>http://localhost:5086/api/todo/e9898d1b-9ad3-4482-ad65-08dc77664fab</code>.</li>
<li>Click the <code>Send</code> button to execute the request.</li>
</ol>
<p>If the request is successful, you'll receive a response similar to the one below:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Todo item with id 21ebe2c2-79c0-45d4-4139-08dc789e3eb2 successfully deleted"</span>
}
</code></pre>
<p>The image below illustrates the successful deletion of a Todo item using Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/PostmanDelete.png" alt="PostmanDelete" width="600" height="400" loading="lazy"></p>
<p>Well done! You've successfully implemented the <code>GetByIdAsync</code>, <code>UpdateTodoAsync</code>, and <code>DeleteTodoAsync</code> methods in the <code>TodoServices</code> and <code>TodoController</code> classes. You've also verified your API endpoints using Postman to ensure they're functioning as expected. You can </p>
<h3 id="heading-source-code">   Source Code  </h3>


<p>The entire source code for this project is readily available in the <a target="_blank" href="https://github.com/Clifftech123/TodoAPI">TodoAPI</a> GitHub repository. I encourage you to delve into the codebase, tinker with various functionalities, and bolster your proficiency in crafting APIs using ASP.NET Core 8.</p>
<h2 id="conclusion"> Conclusion  </h2>

<p>In this guide, we've journeyed through the process of constructing a robust Todo API using the power of ASP.NET Core 8. We initiated our project from scratch, meticulously defining the essential models that form the backbone of our Todo application.</p>
<p>We then created a database context, a crucial step that facilitated our interaction with the database. To further streamline this interaction, we implemented a service layer, effectively abstracting the complexities of direct database operations.</p>
<p>Next, we created our API endpoints. These endpoints serve as the gateways for <code>creating</code>, <code>retrieving</code>, <code>updating</code>, and <code>deleting</code> Todo items, thereby providing comprehensive functionality to our application.</p>
<p>The final stage of our journey involved rigorous testing of our API using Postman. This ensured that our application was not only built as per our design but also functioned as expected, providing a reliable and efficient service.</p>
<p>As we conclude, it's important to remember that the knowledge gained here forms a solid foundation for building more complex and feature-rich APIs. The journey of learning and exploration doesn't end here – it's just the beginning. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an AI-enhanced Task App with React and Appwrite ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you'll build a task manager application that has some artificial intelligence capabilities and is voice-enabled, sortable, and searchable.  As an extra, the application will have dark mode support that respects the users' system pref... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-task-app/</link>
                <guid isPermaLink="false">66b999a9d9d170feecefbbc5</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Appwrite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fatuma Abdullahi ]]>
                </dc:creator>
                <pubDate>Wed, 13 Mar 2024 09:21:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/Group-3--20-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you'll build a task manager application that has some artificial intelligence capabilities and is voice-enabled, sortable, and searchable. </p>
<p>As an extra, the application will have dark mode support that respects the users' system preferences.</p>
<p>The application will be able to create, read, update and delete (CRUD) tasks as well as the ability to view a given task.  </p>
<p>You'll build this application using Appwrite as a backend, React on the frontend, Typescript for type safety and Tailwind CSS for styling.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
    <li><a href="#prerequisites">Prerequisites</a></li>
    <li><a href="#what-is-appwrite">What is Appwrite?</a></li>
    <li><a href="#how-to-set-up-the-appwrite-backend">How to Set Up the Appwrite Backend</a></li>
    <li><a href="#how-to-set-up-the-react-frontend">How to Set up the React Frontend</a></li>
    <li><a href="#how-to-connect-to-the-appwrite-project">How to Connect to the Appwrite Project</a></li>
    <li><a href="#how-to-build-the-task-manager-application">How to Build the Task Manager Application</a>
        <ul>
            <li><a href="#how-to-set-up-routing-with-react-router-v6">How to Set up Routing with React Router V6</a></li>
            <li><a href="#how-to-create-the-form-component">How to Create the Form Component</a></li>
            <li><a href="#how-to-set-up-form-to-create-task">How to Set up Form to Create Task</a></li>
            <li><a href="#how-to-make-the-tasks-editable">How to Make the Tasks Editable</a></li>
            <li><a href="#how-to-enable-viewing-of-tasks">How to Enable Viewing of Tasks</a></li>
            <li><a href="#how-to-auto-generate-descriptions-with-vercel-s-ai-sdk">How to Auto Generate Descriptions with Vercel's AI SDK</a></li>
            <li><a href="#voice-enable-the-application-with-the-react-speech-recognition-package">Voice-enable the Application with the React Speech Recognition Package</a></li>
            <li><a href="#how-to-add-search-functionality-to-the-application">How to Add Search Functionality to the Application</a></li>
            <li><a href="#how-to-add-ability-to-sort-tasks-via-due-date-and-priorityadd-ability-to-sort-tasks-via-due-date-and-priority">How to Add Ability to Sort Tasks via Due Date and Priority</a></li>
            <li><a href="#bonus-add-dark-mode-support">Bonus: Add Dark Mode Support</a></li>

        </ul>
    </li>
    <li><a href="#notes">Notes</a></li>
    <li><a href="#limitations">Limitations</a></li>
</ul>



<h2 id="heading-prerequisitesheading-prerequisites-1"><a class="post-section-overview" href="#heading-prerequisites-1">Prerequisites</a></h2>
<p>You will need the following to be able to build along with this article:</p>
<ul>
<li>Basic programming knowledge</li>
<li>Basic understanding of React, Typescript and Tailwind</li>
<li><a target="_blank" href="https://appwrite.io/">An Appwrite account</a></li>
<li>And a text editor to code along</li>
</ul>
<h2 id="heading-what-is-appwrite">What is Appwrite?</h2>
<p>Appwrite is an <a target="_blank" href="https://opensource.com/resources/what-open-source">open source</a> Backend-as-a-Service (BaaS) platform. A BaaS is a cloud service that packages backend tasks that are typically needed for most applications. </p>
<p>Appwrite offers both a managed database, authentication, functions and storage services and the ability to self-host the entire platform on your own. </p>
<p>Appwrite recently announced a host of new features that makes developers building on their platform lives more straightforward. You can read on that <a target="_blank" href="https://appwrite.io/init">here</a>. </p>
<h2 id="heading-how-to-set-up-the-appwrite-backend">How to Set Up the Appwrite Backend</h2>
<p>Before starting to build the application and interacting with Appwrite, you'll need an Appwrite account and to set up the project.</p>
<p>Once you have the account ready, you will need to create an organization, then create a project within that organization. You can name the project "Tasks App" or any other name you see fit. </p>
<p><strong>Note:</strong> Appwrite cloud restricts you to one organization per account on the hobby/free plan. If you already had an organization, you can go straight to creating a project within your existing organization.</p>
<p>In your Tasks App project, add a web platform and follow the prompts. For the hostname, add "localhost" for now. This is to allow the frontend to bypass <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a> when interacting with the Appwrite backend.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-08-at-14.44.11.png" alt="Image" width="600" height="400" loading="lazy">
<em>A picture of the Appwrite Console showing the "Add a platform" section</em></p>
<p>Copy the installation instructions as you complete setting up the web platform for the project. Keep these safe, you will need them when setting up the frontend. </p>
<p>You should now be in the Appwrite cloud console. Click on the "Databases" on the left sidebar. Then click on the pink "Create database" button. Name your database and leave the autogenerated ID as is.  </p>
<p>Now, click on the "Create collection" button, name your collection "tasks" and leave the autogenerated ID as is. Now, click on the grey "Create attribute" button as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-08-at-15.00.42.png" alt="Image" width="600" height="400" loading="lazy">
<em>A picture of the Appwrite Console showing the "Create attribute" button</em></p>
<p>Add the following attributes: </p>
<ul>
<li>title of type String, give it a size of 49 and make it required</li>
<li>description of type String, give it a size of 200</li>
<li>due_date of type Datetime, make it required</li>
<li>done of type Boolean, give it a default of False</li>
<li>priority of type String, give it a size of 10</li>
</ul>
<p>Finally, you need to set permissions in order for your React frontend to interact with Appwrite services. In this case, allow any one to have access. This is not ideal for production and you can read more about Appwrite permissions <a target="_blank" href="https://appwrite.io/docs/advanced/platform/permissions">here</a>.</p>
<p>Go to the console, click on databases, then your task database and then your tasks collection, then click on settings and scroll down to permissions. Add permissions for "Any" role and give them full CRUD access.</p>
<p>You are now ready to start setting up the frontend and to connect it to the Appwrite project you just completed prepping.</p>
<h2 id="heading-how-to-set-up-the-react-frontend">How to Set up the React Frontend</h2>
<p>Open your text editor to your preferred location. Then open the integrated terminal and run the following command to create a Vite-based application: </p>
<pre><code class="lang-terminal">
//taskwrite is the name of the application
npm create vite@latest taskwrite
</code></pre>
<p>Choose React and then plain Typescript when prompted. This will create a React application with Typescript already set up for you. </p>
<p>Change folders into the newly created "taskwrite" one by running <code>cd taskwrite</code> from the terminal. Run the following command in the same terminal window to add Tailwind to the application:</p>
<pre><code class="lang-terminal">
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>Then in your <strong>tailwind.config.js</strong> file which is in the root of the Taskwrite application, replace the "content" key with <code>content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],</code>. The file should look like this:</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">content</span>: [<span class="hljs-string">"./index.html"</span>, <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>],
    <span class="hljs-attr">theme</span>: {
        <span class="hljs-attr">extend</span>: {},
    },
    <span class="hljs-attr">plugins</span>: [],
};
</code></pre>
<p>This tells Tailwind that it should look for its classes in the index.html file at the root and in files within the <strong>src</strong> folder that end with either <code>.js</code>, <code>.ts</code>, <code>.jsx</code> or <code>.tsx</code> extensions.</p>
<p>Then open the <strong>src</strong> folder and delete the "App.css" file. Open the <strong>index.css</strong> file and replace its contents with the following: </p>
<pre><code class="lang-css">
<span class="hljs-keyword">@import</span> url(<span class="hljs-string">'https://fonts.googleapis.com/css2?family=Inter:wght@100..900&amp;family=Quicksand:wght@300..700&amp;display=swap'</span>);
<span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;

<span class="hljs-keyword">@layer</span> base {
    <span class="hljs-selector-pseudo">:root</span>{
        <span class="hljs-attribute">--base-bg</span>: <span class="hljs-number">#ffffff</span>;
        <span class="hljs-attribute">--btn-bg-primary</span>: <span class="hljs-number">#be185d</span>;
        <span class="hljs-attribute">--btn-bg-primary-hover</span>: <span class="hljs-number">#9d174d</span>;
        <span class="hljs-attribute">--btn-icon-main</span>: <span class="hljs-number">#1e293b</span>;
        <span class="hljs-attribute">--btn-bg-ok</span>: <span class="hljs-number">#4ade80</span>;
        <span class="hljs-attribute">--btn-bg-light-ok</span>: <span class="hljs-number">#bbf7d0</span>;
        <span class="hljs-attribute">--btn-bg-light</span>: <span class="hljs-number">#e5e7eb</span>;
        <span class="hljs-attribute">--low-priority</span>: <span class="hljs-number">#facc15</span>;
        <span class="hljs-attribute">--medium-priority</span>: <span class="hljs-number">#fb923c</span>;
        <span class="hljs-attribute">--high-priority</span>: <span class="hljs-number">#f87171</span>;
        <span class="hljs-attribute">--text-error</span>: <span class="hljs-number">#dc2626</span>;
        <span class="hljs-attribute">--text-ok</span>: <span class="hljs-number">#16a34a</span>;
        <span class="hljs-attribute">--text-main</span>: <span class="hljs-number">#262626</span>;
        <span class="hljs-attribute">--border-container</span>: <span class="hljs-number">#9ca3af</span>;
        <span class="hljs-attribute">--border-input</span>: <span class="hljs-number">#1e293b</span>;
        <span class="hljs-attribute">--border-error</span>: <span class="hljs-number">#dc2626</span>;
    }

    <span class="hljs-selector-tag">body</span>{
        <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--base-bg);
        <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-main);    
    }

    <span class="hljs-selector-id">#date</span><span class="hljs-selector-pseudo">::-webkit-calendar-picker-indicator</span> {
        <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--btn-bg-light); 
    }
}
</code></pre>
<p>This adds some custom css variables to the application. The variables map to Tailwind colors. </p>
<p>Next, paste the following into the <strong>tailwind.config.js</strong> at the root of the application:</p>
<pre><code class="lang-typescript">
<span class="hljs-comment">/** @type {import('tailwindcss').Config} */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    content: [<span class="hljs-string">"./index.html"</span>, <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>],
    theme: {
        extend: {
            textColor: {
                error: <span class="hljs-string">"var(--text-error)"</span>,
                ok: <span class="hljs-string">"var(--text-ok)"</span>,
                main: <span class="hljs-string">"var(--text-main)"</span>,
                iconColor: <span class="hljs-string">"var(--btn-icon-main)"</span>,
            },
            backgroundColor: {
                base: <span class="hljs-string">"var(--base-bg)"</span>,
                primary: <span class="hljs-string">"var(--btn-bg-primary)"</span>,
                primaryHover: <span class="hljs-string">"var(--btn-bg-primary-hover)"</span>,
                ok: <span class="hljs-string">"var(--btn-bg-ok)"</span>,
                lightOk: <span class="hljs-string">"var(--btn-bg-light-ok)"</span>,
                light: <span class="hljs-string">"var(--btn-bg-light)"</span>,
                lowPriority: <span class="hljs-string">"var(--low-priority)"</span>,
                mediumPriority: <span class="hljs-string">"var(--medium-priority)"</span>,
                highPriority: <span class="hljs-string">"var(--high-priority)"</span>,
            },
            borderColor: {
                container: <span class="hljs-string">"var(--border-container)"</span>,
                input: <span class="hljs-string">"var(--border-input)"</span>,
                error: <span class="hljs-string">"var(--border-error)"</span>,
            },
        },
    },
    plugins: [],
};
</code></pre>
<p>This ties the CSS variables to the tailwind config and makes them available to use in our application.</p>
<p>Now Taskwrite is set up with React, Typescript and Tailwind.</p>
<h2 id="heading-how-to-connect-to-the-appwrite-project">How to Connect to the Appwrite Project</h2>
<p>Firstly, you need to add the Appwrite dependency to the React application. Run the following command in the terminal window to do that: <code>npm i appwrite</code>.</p>
<p>Next thing is to set up the Appwrite keys we need as environment variables. In the <strong>.gitignore</strong> file at the root of the application, add <code>*.env</code> at the top of the file then save. This will ensure that the <strong>.env</strong> file you'll create is not added to version control. </p>
<p>Now, create a <strong>.env</strong> file at the root of the React application and paste the following variables in it:</p>
<pre><code class="lang-env">
//replace the right hand side of the equal sign with the correct values from your Appwrite project.
VITE_APPWRITE_URL=YOUR-APPWRITE-API-ENDPOINT
VITE_APPWRITE_PROJ_ID=YOUR-APPWRITE-PROJECT-ID
</code></pre>
<p>You can get the necessary values in your Appwrite console. Click on the settings tab at the bottom of the left sidebar and copy API credentials. </p>
<p>Next, create a utils folder in the <strong>src</strong> folder of the React application. Add a file called <strong>appwrite.ts</strong> within it and paste the following config information:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { Client, Databases } <span class="hljs-keyword">from</span> <span class="hljs-string">"appwrite"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> Client();

client
    .setEndpoint(<span class="hljs-keyword">import</span>.meta.env.VITE_APPWRITE_URL)
    .setProject(<span class="hljs-keyword">import</span>.meta.env.VITE_APPWRITE_PROJ_ID);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> databases = <span class="hljs-keyword">new</span> Databases(client);

<span class="hljs-keyword">export</span> { ID } <span class="hljs-keyword">from</span> <span class="hljs-string">"appwrite"</span>;
</code></pre>
<p>You are ready to test that the React application is connected to the Appwrite project. Replace everything in the <strong>App.tsx</strong> file within the <strong>src</strong> folder with the following code:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { client } <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils/appwrite"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Appwrite"</span>, client);
    <span class="hljs-keyword">return</span> &lt;div className=<span class="hljs-string">"text-purple-500 text-center font-bold text-      5xl"</span>&gt;App&lt;/div&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Then open an integrated terminal window and run the following command: <code>npm run dev</code>. This will run your React application at this URL: <a target="_blank" href="http://localhost:5173/">http://localhost:5173/</a>. Open the URL in a browser window and open the browser console. </p>
<p>You should see a large purple text "App" in the center of the screen and the Appwrite client logged in the console like so: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-08-at-16.36.36.png" alt="Image" width="600" height="400" loading="lazy">
<em>The web app running in the browser</em></p>
<p>Now you need to grab the database ID and the collection ID from the Appwrite console. Click on the databases tab on the left sidebar, hover on the database ID value and click to copy it. </p>
<p>Go back to your <strong>.env</strong> file and add an entry like so:</p>
<pre><code class="lang-env">
//replace the right hand side of the equal sign with the correct values from your Appwrite project.
VITE_APPWRITE_URL=YOUR-APPWRITE-API-ENDPOINT
VITE_APPWRITE_PROJ_ID=YOUR-APPWRITE-PROJECT-ID
//new entry below
VITE_APPWRITE_DB_ID=YOUR-APPWRITE-DB-ID
</code></pre>
<p>Lastly, go back to the console and click through the database to get to the collections. Hover and copy collection ID like before, then add it just below the database ID in your env file like so: </p>
<pre><code class="lang-env">
VITE_APPWRITE_DB_ID=YOUR-APPWRITE-DB-ID
VITE_APPWRITE_COLLECTION_ID=YOUR-APPWRITE-COLLECTION-ID
</code></pre>
<p>With that, the set up part of building Taskwrite is complete.</p>
<h2 id="heading-how-to-build-the-task-manager-application">How to Build the Task Manager Application</h2>
<p>To make it easier to work with Typescript, you will need to add interfaces that correspond with the shape of the Appwrite database response. </p>
<p>In your <strong>src</strong> folder, create a folder called <strong>models</strong> and in it, create a file called <strong>interface.ts</strong>. Paste the following in the file:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { Models } <span class="hljs-keyword">from</span> <span class="hljs-string">"appwrite"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> IPayload {
    title: <span class="hljs-built_in">string</span>;
    description: <span class="hljs-built_in">string</span>;
    due_date: <span class="hljs-built_in">Date</span>;
    priority?: <span class="hljs-built_in">string</span>;
    done?: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> ITask <span class="hljs-keyword">extends</span> Models.Document {
    title: <span class="hljs-built_in">string</span>;
    description: <span class="hljs-built_in">string</span>;
    due_date: <span class="hljs-built_in">Date</span>;
    priority?: <span class="hljs-built_in">string</span>;
    done: <span class="hljs-built_in">boolean</span>;
}
</code></pre>
<p>Here, you are defining an interface called "IPayload" with the same attributes as the task we defined in the Appwrite project. Then you are defining another interface called "ITask" that extends the built in base Model from Appwrite. </p>
<p>This means that ITask has both the attributes of the task we defined before and the built in base attributes that Appwrite collections come with.</p>
<p>Next, in your <strong>utils</strong> folder add a file called <strong>db.ts</strong> and paste the following in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { ID, databases } <span class="hljs-keyword">from</span> <span class="hljs-string">"./appwrite"</span>;
<span class="hljs-keyword">import</span> { IPayload } <span class="hljs-keyword">from</span> <span class="hljs-string">"../models/interface"</span>;

<span class="hljs-keyword">const</span> dbID: <span class="hljs-built_in">string</span> = <span class="hljs-keyword">import</span>.meta.env.VITE_APPWRITE_DB_ID;
<span class="hljs-keyword">const</span> collectionID: <span class="hljs-built_in">string</span> = <span class="hljs-keyword">import</span>.meta.env.VITE_APPWRITE_COLLECTION_ID;

<span class="hljs-keyword">const</span> createDocument = <span class="hljs-keyword">async</span> (payload: IPayload) =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> databases.createDocument(dbID, collectionID, ID.unique(), {
        ...payload,
    });

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

<span class="hljs-keyword">const</span> readDocuments = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID);

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

<span class="hljs-keyword">const</span> updateDocument = <span class="hljs-keyword">async</span> (payload: IPayload, id: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> databases.updateDocument(dbID, collectionID, id, {
        ...payload,
    });

    <span class="hljs-keyword">return</span> res;
};
<span class="hljs-keyword">const</span> deleteDocument = <span class="hljs-keyword">async</span> (id: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> databases.deleteDocument(dbID, collectionID, id);

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

<span class="hljs-keyword">export</span> { createDocument, readDocuments, updateDocument, deleteDocument };
</code></pre>
<p>This file defines four functions corresponding with the CRUD operations. The naming of the functions map to which operation it performs. For all functions, you pass the collection and database IDs so that Appwrite knows which resources to operate on.</p>
<p>To create a task on the Appwrite database, you pass an object with the shape of a task to the function and ask it to create a unique ID for each new task it creates. </p>
<p>To update a task, you pass it a task object similar to create but we also pass it the unique ID of the task to be updated.</p>
<p>To read all tasks from the Appwrite, you call the "listDocuments" function and to delete a task you pass the ID corresponding to the task to be deleted.</p>
<h3 id="heading-how-to-set-up-routing-with-react-router-v6">How to Set Up Routing with React Router V6</h3>
<p>The Taskwrite application will have two routes and a navigation menu to help with that. To add navigation, open an integrated terminal and run the following command to install the React Router library: <code>npm i react-router-dom</code>.</p>
<p>Now, go to the <strong>main.tsx</strong> file in the <strong>src</strong> folder and paste the following in it: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.tsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)!).render(
    &lt;React.StrictMode&gt;
        &lt;BrowserRouter&gt;
            &lt;App /&gt;
        &lt;/BrowserRouter&gt;
    &lt;/React.StrictMode&gt;
);
</code></pre>
<p>Then go to the <strong>App.tsx</strong> file in <strong>src</strong> folder and paste the following in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> { Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> Task <span class="hljs-keyword">from</span> <span class="hljs-string">"./routes/Task"</span>;
<span class="hljs-keyword">import</span> Index <span class="hljs-keyword">from</span> <span class="hljs-string">"./routes/Index"</span>;
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;&gt;
            &lt;Navbar/&gt;
            &lt;Routes&gt;
                &lt;Route path=<span class="hljs-string">"/"</span> element={&lt;Index /&gt;} /&gt;
                &lt;Route path=<span class="hljs-string">"/tasks"</span> element={&lt;Task /&gt;} /&gt;
            &lt;/Routes&gt;
        &lt;/&gt;
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>You now need to create the referenced component above. In the <strong>src</strong> folder, create a folder called <strong>routes</strong> and within it create two files called <strong>Index.tsx</strong> and <strong>Task.tsx</strong>.  </p>
<p>In <strong>Index.tsx</strong>, paste the following: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        &lt;main className=<span class="hljs-string">"container mx-auto"</span>&gt;
            &lt;section className=<span class="hljs-string">"max-w-5xl mx-auto m-12 p-16"</span>&gt;
                &lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
                    AI-enhanced, Voice-enabled, Searchable Task Manager
                &lt;/h1&gt;
            &lt;/section&gt;
        &lt;/main&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index;
</code></pre>
<p>And in <strong>Task.tsx</strong>, paste the following:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> Task = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        &lt;main className=<span class="hljs-string">"container mx-auto"</span>&gt;
            &lt;section className=<span class="hljs-string">"max-w-5xl mx-auto m-12 p-16"</span>&gt;
                &lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
                    Your Tasks
                &lt;/h1&gt;
            &lt;/section&gt;
        &lt;/main&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Task;
</code></pre>
<p>Now, create a components folder in the <strong>src</strong> folder and add a file within it called <strong>Navbar.tsx</strong>. Paste the following in that file: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { Link, useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> { PencilIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/24/solid"</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./Button"</span>;

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> navigate = useNavigate();

    <span class="hljs-keyword">return</span> (
        &lt;nav className=<span class="hljs-string">"py-4 border-b-2 border-container shadow-md shadow-gray-400 w-full fixed top-0 bg-base"</span>&gt;
            &lt;ul className=<span class="hljs-string">"flex items-center justify-between  w-11/12 mx-auto"</span>&gt;
                &lt;Link to=<span class="hljs-string">"/"</span>&gt;
                    &lt;Button
                        content={{
                            text: <span class="hljs-string">"Taskwrite"</span>,
                            icon: PencilIcon,
                        }}
                        textClasses=<span class="hljs-string">"font-semibold text-main"</span>
                        iconClasses=<span class="hljs-string">"text-main"</span>
                    /&gt;
                &lt;/Link&gt;
                &lt;/Link&gt;
                &lt;div className=<span class="hljs-string">"flex items-center justify-between gap-6"</span>&gt;
                    &lt;Link
                        to=<span class="hljs-string">"/tasks"</span>
                        className=<span class="hljs-string">"font-semibold hover:scale-105 transition duration-300 ease-in-out"</span>
                    &gt;
                        View Tasks
                    &lt;/Link&gt;
                &lt;/div&gt;
            &lt;/ul&gt;
        &lt;/nav&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>This file contains navigation menu that switches between the two pages. You will need to create the <code>Button</code> component referenced above and add the Hero icons package.   </p>
<p>In an integrated terminal, run the following to add Hero icons: <code>npm i @heroicons/react</code> . Next, add a new file called <strong>Button.tsx</strong> in the components folder. Paste the following within that file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">interface</span> ButtonProps {
    extraBtnClasses?: <span class="hljs-built_in">string</span>;
    textColor?: <span class="hljs-built_in">string</span>;
    handleClick?: <span class="hljs-function">(<span class="hljs-params">e: React.MouseEvent&lt;HTMLButtonElement&gt;</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
    title?: <span class="hljs-built_in">string</span>;
    disable?: <span class="hljs-built_in">boolean</span>;
    <span class="hljs-keyword">type</span>?: <span class="hljs-string">"button"</span> | <span class="hljs-string">"submit"</span> | <span class="hljs-string">"reset"</span>;
    children: ReactNode;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{
    extraBtnClasses,
    textColor,
    handleClick,
    title,
    disable,
    <span class="hljs-keyword">type</span> = "button",
    children,
}: ButtonProps</span>) </span>{
    <span class="hljs-keyword">const</span> handleClickProp = <span class="hljs-keyword">type</span> === <span class="hljs-string">"submit"</span> ? <span class="hljs-literal">undefined</span> : handleClick;

    <span class="hljs-keyword">return</span> (
        &lt;button
            <span class="hljs-keyword">type</span>={<span class="hljs-keyword">type</span>}
            title={title ?? <span class="hljs-string">""</span>}
            onClick={handleClickProp}
            disabled={disable}
            className={<span class="hljs-string">`flex gap-2 items-center text-iconColor <span class="hljs-subst">${extraBtnClasses}</span> <span class="hljs-subst">${
                textColor ?? <span class="hljs-string">""</span>
            }</span> rounded-md px-2 py-1 hover:scale-105 transition duration-300 ease-in-out`</span>}
        &gt;
            {children}
        &lt;/button&gt;
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Button;
</code></pre>
<p>This file describes a shared button component and defines the props that it will accept.</p>
<p>Go back and fix any import errors and re-run the application by running <code>npm run dev</code>, you should see something like this: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-08-at-18.23.45.png" alt="Image" width="600" height="400" loading="lazy">
<em>app running with npm run dev command</em></p>
<h3 id="heading-how-to-create-the-form-component">How to Create the Form Component</h3>
<p>Add a new file called <strong>AddTask.tsx</strong> in the components folder and paste the following into it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Select <span class="hljs-keyword">from</span> <span class="hljs-string">"./Select"</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./Button"</span>;

<span class="hljs-keyword">const</span> AddTask = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [titleVal, setTitleVal] = useState(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [textAreaVal, setTextAreaVal] = useState(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [dueDate, setDueDate] = useState(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>());

    <span class="hljs-keyword">const</span> priorityArray = [<span class="hljs-string">"low"</span>, <span class="hljs-string">"medium"</span>, <span class="hljs-string">"high"</span>];

    <span class="hljs-keyword">const</span> [priority, setPriority] = useState(priorityArray[<span class="hljs-number">0</span>]);

    <span class="hljs-keyword">return</span> (
        &lt;form id=<span class="hljs-string">"form"</span> className=<span class="hljs-string">"m-8"</span>&gt;
            &lt;div className=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;
                &lt;label htmlFor=<span class="hljs-string">"title"</span>&gt;Task Title&lt;/label&gt;
                &lt;input
                    <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
                    id=<span class="hljs-string">"title"</span>
                    placeholder=<span class="hljs-string">"Title of your task"</span>
                    value={titleVal}
                    onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setTitleVal(e.target.value)}
                    className=<span class="hljs-string">"bg-inherit border rounded-sm p-2 focus:outline-none focus:ring-1 border-input focus:ring-slate-900"</span>
                /&gt;
            &lt;/div&gt;
            &lt;div className=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;
                &lt;label htmlFor=<span class="hljs-string">"description"</span> className=<span class="hljs-string">"mb-1"</span>&gt;
                    Task Description
                &lt;/label&gt;
                &lt;textarea
                    id=<span class="hljs-string">"description"</span>
                    placeholder=<span class="hljs-string">"Describe your task"</span>
                    maxLength={<span class="hljs-number">200</span>}
                    value={textAreaVal}
                    onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setTextAreaVal(e.target.value)}
                    className=<span class="hljs-string">"bg-inherit border rounded-sm p-2 h-32 resize-none focus:outline-none focus:ring-1 border-input focus:ring-slate-900"</span>
                /&gt;
            &lt;/div&gt;
            &lt;div className=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;
                &lt;label htmlFor=<span class="hljs-string">"description"</span> className=<span class="hljs-string">"mb-1"</span>&gt;
                    Task Priority
                &lt;/label&gt;
                &lt;Select
                    defaultSelectValue={priority}
                    selectOptions={priorityArray}
                    handleSelectChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setPriority(e.target.value)}
                /&gt;
            &lt;/div&gt;
            &lt;div className=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;
                &lt;label htmlFor=<span class="hljs-string">"description"</span> className=<span class="hljs-string">"mb-1"</span>&gt;
                    Task Due <span class="hljs-built_in">Date</span>
                &lt;/label&gt;
                &lt;input
                    <span class="hljs-keyword">type</span>=<span class="hljs-string">"date"</span>
                    id=<span class="hljs-string">"date"</span>
                    value={dueDate!.toISOString().split(<span class="hljs-string">"T"</span>)[<span class="hljs-number">0</span>]}
                    min={<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString().split(<span class="hljs-string">"T"</span>)[<span class="hljs-number">0</span>]}
                    onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setDueDate(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(e.target.value))}
                    className=<span class="hljs-string">"bg-inherit border rounded-sm border-input p-2 focus:outline-none focus:ring-1 focus:ring-slate-900 invalid:focus:ring-red-600"</span>
                /&gt;
            &lt;/div&gt;
            &lt;Button
                <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>
                content={{
                    text: <span class="hljs-string">"Add Task"</span>,
                }}
                extraBtnClasses=<span class="hljs-string">"bg-pink-700 justify-center text-white font-semibold px-4 py-2 outline-1 hover:bg-pink-800 focus:ring-1 focus:ring-pink-800 w-full"</span>
            /&gt;
        &lt;/form&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddTask;
</code></pre>
<p>Now create a new file in components called <strong>Select.tsx</strong>, paste the following in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">interface</span> SelectProps {
    defaultSelectValue: <span class="hljs-built_in">string</span>;
    selectOptions: <span class="hljs-built_in">string</span>[];
    handleSelectChange: <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLSelectElement&gt;</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">const</span> Select = <span class="hljs-function">(<span class="hljs-params">{
    defaultSelectValue,
    handleSelectChange,
    selectOptions,
}: SelectProps</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [selectVal, setSelectVal] = useState(defaultSelectValue);
    <span class="hljs-keyword">return</span> (
        &lt;select
            value={selectVal}
            onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
                setSelectVal(e.target.value);
                handleSelectChange(e);
            }}
            className=<span class="hljs-string">"bg-inherit border rounded-sm border-input p-2 focus:outline-none focus:ring-1 focus:ring-slate-900 cursor-pointer"</span>
        &gt;
            {selectOptions.map(<span class="hljs-function">(<span class="hljs-params">option</span>) =&gt;</span> (
                &lt;option key={option} value={option}&gt;
                    {option.charAt(<span class="hljs-number">0</span>).toUpperCase() + option.slice(<span class="hljs-number">1</span>)}
                &lt;/option&gt;
            ))}
        &lt;/select&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Select;
</code></pre>
<p>This defines a <code>Select</code> component and its props. The <code>Select</code> component props are a function for handling change, an array of options and the default value it should display. </p>
<p>Now, import the <code>AddTask</code> component in the <strong>Index.tsx</strong> file between the <code>h1</code> tags like so: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> AddTask <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/AddTask"</span>;

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> (
        &lt;main className=<span class="hljs-string">"container mx-auto"</span>&gt;
            &lt;section className=<span class="hljs-string">"max-w-5xl mx-auto m-12 p-16"</span>&gt;
                &lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
                    AI-enhanced, Voice-enabled, Searchable Task Manager
                &lt;/h1&gt;
                &lt;AddTask /&gt;
            &lt;/section&gt;
        &lt;/main&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index;
</code></pre>
<p>Your application should now display the form:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-08-at-18.57.25.png" alt="Image" width="600" height="400" loading="lazy">
<em>task app form</em></p>
<h3 id="heading-how-to-set-up-form-to-create-task">How to Set Up Form to Create Task</h3>
<p>To make the form functional, you need to hook it up to a submit function that will call the create function defined in the <strong>db.ts</strong> file. </p>
<p>Additionally, you will need to validate the form to avoid sending bad data and having Appwrite send errors back to the React application.</p>
<p>In the <code>AddTask</code> component file, paste the following code above the <code>return</code> statement and below the <code>setPriority</code> useState:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [priority, setPriority] = useState(priorityArray[<span class="hljs-number">0</span>]);

<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> navigate = useNavigate();

<span class="hljs-keyword">const</span> [isSubmitting, setIsSubmitting] = useState(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> [titleValidationError, setTitleValidationError] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> handleTitleChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> {
        setTitleVal(e.target.value);

        <span class="hljs-keyword">if</span> (e.target.value.trim() !== <span class="hljs-string">""</span>) {
            setTitleValidationError(<span class="hljs-string">""</span>);
        }
    };

    <span class="hljs-keyword">const</span> handleSubmitTask = <span class="hljs-keyword">async</span> (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {
        e.preventDefault();
        setIsSubmitting(<span class="hljs-literal">true</span>);

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">if</span> (!titleVal) {
                setTitleValidationError(<span class="hljs-string">"Please provide at least a title for the task"</span>);
                <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> setTitleValidationError(<span class="hljs-string">""</span>), <span class="hljs-number">2000</span>);
                setIsSubmitting(<span class="hljs-literal">false</span>);
                <span class="hljs-keyword">return</span>;
            }

            <span class="hljs-keyword">if</span> (titleVal.length &gt; <span class="hljs-number">49</span>) {
                setTitleValidationError(
                    <span class="hljs-string">"Title too long. It can only be 49 characters long"</span>
                );
                <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> setTitleValidationError(<span class="hljs-string">""</span>), <span class="hljs-number">2000</span>);
                setIsSubmitting(<span class="hljs-literal">false</span>);
                <span class="hljs-keyword">return</span>;
            }

            <span class="hljs-keyword">const</span> payload: IPayload = {
                title: titleVal,
                description: textAreaVal,
                due_date: dueDate,
                priority: priority,
            };

            <span class="hljs-keyword">await</span> createDocument(payload);

            <span class="hljs-comment">// reset form</span>
            setTitleVal(<span class="hljs-string">""</span>);
            setTextAreaVal(<span class="hljs-string">""</span>);
            setDueDate(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>());
            setPriority(priorityArray[<span class="hljs-number">0</span>]);
            setTitleValidationError(<span class="hljs-string">""</span>);
            setIsSubmitting(<span class="hljs-literal">false</span>);
            navigate(<span class="hljs-string">"/tasks"</span>);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error in handleSubmitTask:"</span>, error);
            setIsSubmitting(<span class="hljs-literal">false</span>);
        }
    };

    <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">//rest of the code unchanged below</span>
</code></pre>
<p>Then replace the <code>return</code> statement with the following code:</p>
<pre><code>
<span class="hljs-keyword">return</span> (
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmitTask}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"m-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span>&gt;</span>Task Title<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Title of your task"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{titleVal}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleTitleChange}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">bg-inherit</span> <span class="hljs-attr">border</span> <span class="hljs-attr">rounded-sm</span> <span class="hljs-attr">p-2</span> <span class="hljs-attr">focus:outline-none</span>                         <span class="hljs-attr">focus:ring-1</span> ${
                    <span class="hljs-attr">titleValidationError</span>
                    ? "<span class="hljs-attr">border-error</span> <span class="hljs-attr">focus:ring-red-500</span> <span class="hljs-attr">invalid:focus:ring-red-</span>                         <span class="hljs-attr">600</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">border-input</span> <span class="hljs-attr">focus:ring-slate-900</span>"
            }`}
        /&gt;</span>
        {titleValidationError &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-error mt-1"</span>&gt;</span>{titleValidationError}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
            Task Description
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"description"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Describe your task"</span>
            <span class="hljs-attr">maxLength</span>=<span class="hljs-string">{200}</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{textAreaVal}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTextAreaVal(e.target.value)}
            className={`bg-inherit border rounded-sm p-2 h-32 resize-none                             focus:outline-none focus:ring-1 ${
                        textAreaVal.length &gt; 197
                        ? "border-error focus:ring-red-500 invalid:focus:ring-                             red-600"
                        : "border-input focus:ring-slate-900"
                }`}
        /&gt;
        {textAreaVal.length &gt; 197 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-error mt-1"</span>&gt;</span>
            Warning description getting too long. Can only be 200 characters
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
            Task Priority
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Select</span>
            <span class="hljs-attr">defaultSelectValue</span>=<span class="hljs-string">{priority}</span>
            <span class="hljs-attr">selectOptions</span>=<span class="hljs-string">{priorityArray}</span>
            <span class="hljs-attr">handleSelectChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPriority(e.target.value)}
        /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col mb-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-1"</span>&gt;</span>
            Task Due Date
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{dueDate!.toISOString().split(</span>"<span class="hljs-attr">T</span>")[<span class="hljs-attr">0</span>]}
            <span class="hljs-attr">min</span>=<span class="hljs-string">{new</span> <span class="hljs-attr">Date</span>()<span class="hljs-attr">.toISOString</span>()<span class="hljs-attr">.split</span>("<span class="hljs-attr">T</span>")[<span class="hljs-attr">0</span>]}
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setDueDate(new Date(e.target.value))}
                className="bg-inherit border rounded-sm border-input p-2                                      focus:outline-none focus:ring-1 focus:ring-slate-                               900 invalid:focus:ring-red-600"
        /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
        <span class="hljs-attr">disable</span>=<span class="hljs-string">{isSubmitting}</span>
        <span class="hljs-attr">extraBtnClasses</span>=<span class="hljs-string">"bg-primary justify-center text-white font-semibold px-4 py-2 outline-1 hover:bg-primaryHover focus:ring-1 focus:ring-pink-800 w-full"</span>
    &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
            Add Task
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
);
</code></pre><p>Fix import errors and your application should now be validating title and description as well as creating the task then sending you to the "/tasks" route. You can check the Appwrite console to confirm that the task has been created. </p>
<h3 id="heading-how-set-up-read-and-delete-tasks">How Set Up Read and Delete Tasks</h3>
<p>Open the <strong>Task.jsx</strong> file in the routes folder within <strong>src</strong> folder, and add the following code above the <code>return</code> like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [tasks, setTasks] = useState&lt;ITask[]&gt;([]);
<span class="hljs-keyword">const</span> [tasksError, setTasksError] = useState(<span class="hljs-string">""</span>);

useEffect(<span class="hljs-function">() =&gt;</span> {
        getTasks()
        .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
        setTasks(res.reverse());
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(err);
        setTasksError(<span class="hljs-string">"Error fetching tasks, please try again"</span>);
        });
    }, []);

<span class="hljs-keyword">return</span> (
<span class="hljs-comment">//rest of code</span>
</code></pre>
<p>Here, the file is setting some local state using useState to hold the tasks and set any potential task related errors.</p>
<p>Now replace the code in the <code>return</code> with the following code:</p>
<pre><code class="lang-typescript">

&lt;main className=<span class="hljs-string">"container mx-auto"</span>&gt;
    &lt;section className=<span class="hljs-string">"max-w-5xl mx-auto m-12 p-16"</span>&gt;
        &lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
        Your Tasks
        &lt;/h1&gt;
        {tasksError ? (
            &lt;span className=<span class="hljs-string">"m-8 text-error"</span>&gt;{tasksError}&lt;/span&gt;
        ) : (
            &lt;div className=<span class="hljs-string">"flex flex-col md:flex-row justify-between"</span>&gt;
                &lt;div className=<span class="hljs-string">"flex-1"</span>&gt;
                    &lt;h3 className=<span class="hljs-string">"text-2xl font-bold m-8"</span>&gt;Pending Tasks&lt;/h3&gt;
                    &lt;div&gt;
                         {tasks
                             .filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> !task.done)
                             .map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> (
                                &lt;TaskItem key={task.$id} task={task} /&gt;
                         ))}
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;div className=<span class="hljs-string">"flex-1"</span>&gt;
                    &lt;h3 className=<span class="hljs-string">"text-2xl font-bold m-8"</span>&gt;Completed Tasks&lt;/h3&gt;
                    &lt;div&gt;
                        {tasks
                            .filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task.done)
                            .map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> (
                                &lt;TaskItem key={task.$id} task={task} /&gt;
                        ))}
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        )}
    &lt;/section&gt;
&lt;/main&gt;
</code></pre>
<p>You now need to create the <code>getTasks()</code> function and the <code>TaskItem</code> component. In the components folder, create a file called <strong>TaskItem.tsx</strong> and paste the following code in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">interface</span> TaskItemProps {
    task: ITask;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskItem</span>(<span class="hljs-params">{ task }: TaskItemProps</span>) </span>{
    <span class="hljs-keyword">return</span> (
    &lt;&gt;
        &lt;div className=<span class="hljs-string">"m-8 cursor-pointer border border-container rounded-md p-4 hover:shadow-lg transition duration-300 ease-in-out max-h-96"</span>&gt;
            &lt;section
            key={task.$id}
            className=<span class="hljs-string">"flex flex-col justify-between gap-2 my-4 h-full"</span>
            &gt;
            &lt;section className=<span class="hljs-string">"flex gap-4 items-center justify-between flex-wrap"</span>&gt;
                {task.priority &amp;&amp; (
                &lt;span&gt;
                    &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Priority: &lt;/span&gt;
                        &lt;span
                            className={<span class="hljs-string">`<span class="hljs-subst">${
                            task.priority === <span class="hljs-string">"low"</span>
                            ? <span class="hljs-string">"bg-lowPriority text-iconColor"</span>
                            : task.priority === <span class="hljs-string">"medium"</span>
                            ? <span class="hljs-string">"bg-mediumPriority text-iconColor"</span>
                            : <span class="hljs-string">"bg-highPriority text-iconColor"</span>
                            }</span> py-1 px-2 rounded-md`</span>}
                        &gt;
                            {task.priority}
                        &lt;/span&gt;
                &lt;/span&gt;
                )}
                &lt;div className=<span class="hljs-string">"flex gap-2 py-1 ml-auto"</span>&gt;
                    &lt;Button
                        handleClick={<span class="hljs-function">() =&gt;</span> handleEdit(task)}
                        extraBtnClasses=<span class="hljs-string">"bg-ok"</span>
                    &gt;
                        &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Edit&lt;/span&gt;
                        &lt;PencilSquareIcon height={<span class="hljs-number">25</span>} className=<span class="hljs-string">"hidden lg:flex"</span> /&gt;
                    &lt;/Button&gt;
                    &lt;Button
                        handleClick={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleDelete(e, task.$id)}
                        extraBtnClasses=<span class="hljs-string">"bg-highPriority"</span>
                    &gt;
                        &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Delete&lt;/span&gt;
                        &lt;TrashIcon height={<span class="hljs-number">25</span>} className=<span class="hljs-string">"hidden lg:flex"</span> /&gt;
                    &lt;/Button&gt;
                &lt;/div&gt;
            &lt;/section&gt;
            &lt;section className=<span class="hljs-string">""</span>&gt;
                &lt;h2 className=<span class="hljs-string">"text-xl font-medium py-2 break-words"</span>&gt;
                    {task.title}
                &lt;/h2&gt;
                &lt;p className=<span class="hljs-string">"py-1 mb-4 min-h-16 break-words"</span>&gt;
                    {task.description.length &gt; <span class="hljs-number">70</span>
                        ? task.description.substring(<span class="hljs-number">0</span>, <span class="hljs-number">70</span>) + <span class="hljs-string">"..."</span>
                        : task.description}
                &lt;/p&gt;
                &lt;span className=<span class="hljs-string">"font-extralight mt-2"</span>&gt;
                    &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Due on: &lt;/span&gt;
                        &lt;span className=<span class="hljs-string">"underline"</span>&gt;{<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(
                            task.due_date
                        ).toLocaleDateString()}</span>`</span>}
                    &lt;/span&gt;
                &lt;/span&gt;
                &lt;/section&gt;
                &lt;section className=<span class="hljs-string">"flex justify-between"</span>&gt;
                    {task.done ? (
                        &lt;span className=<span class="hljs-string">"items-center text-ok font-bol ml-auto"</span>&gt;
                            Completed
                        &lt;/span&gt;
                    ) : (
                    &lt;div className=<span class="hljs-string">"flex items-center ml-auto hover:scale-105 transition duration-300 ease-in-out"</span>&gt;
                        &lt;label htmlFor=<span class="hljs-string">"done"</span> className=<span class="hljs-string">"mr-2 font-light"</span>&gt;
                            Mark <span class="hljs-keyword">as</span> complete
                        &lt;/label&gt;
                        &lt;input
                            <span class="hljs-keyword">type</span>=<span class="hljs-string">"checkbox"</span>
                            checked={isDone}
                            onClick={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e.stopPropagation()}
                            onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
                            setIsDone(e.target.checked);
                            handleCheckbox(task, task.$id, e);
                        }}
                            className=<span class="hljs-string">"size-5 accent-pink-600 rounded-sm"</span>
                    /&gt;
                &lt;/div&gt;
                )}
                &lt;/section&gt;
            &lt;/section&gt;
        &lt;/div&gt;
    &lt;/&gt;
    );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TaskItem;
</code></pre>
<p>This gives the file some markup to display. It divides the page into two columns, one for the pending tasks and one for the completed tasks, and it handles responsiveness of the page.</p>
<p>In order to get rid of the errors, paste the following code just before the <code>return</code> statement like so: </p>
<pre><code class="lang-typescript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskItem</span>(<span class="hljs-params">{ task }: TaskItemProps</span>) </span>{

<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> [isDone, setIsDone] = useState(<span class="hljs-literal">false</span>);

<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-keyword">async</span> (
        currentTaskId: <span class="hljs-built_in">string</span>
    ) =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">await</span> deleteDocument(currentTaskId);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(error);
        }
};

<span class="hljs-keyword">const</span> handleCheckbox = <span class="hljs-keyword">async</span> (
        currentTask: IPayload,
        id: <span class="hljs-built_in">string</span>,
        checkedVal: <span class="hljs-built_in">boolean</span>
    ) =&gt; {
        <span class="hljs-keyword">if</span> (!checkedVal) <span class="hljs-keyword">return</span>;

        <span class="hljs-keyword">const</span> payload: IPayload = {
        title: currentTask.title,
        description: currentTask.description,
        due_date: currentTask.due_date,
        priority: currentTask.priority,
        done: checkedVal,
        };

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">await</span> updateDocument(payload, id);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(error);
        }
};

<span class="hljs-comment">//rest of code below untouched</span>
<span class="hljs-keyword">return</span> (
......
</code></pre>
<p>This adds the ability to delete a task item and the ability to mark it as complete. </p>
<p>Create a new file in the <strong>utils</strong> folder and call it <strong>shared.ts</strong>. This file will house any function that will be called in more than two places in the application. </p>
<p>The <code>getTasks</code> function is one such repetitive function, so it will be placed in the <strong>shared.ts</strong> file. Paste the following code into it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { readDocuments } <span class="hljs-keyword">from</span> <span class="hljs-string">"./db"</span>;
<span class="hljs-keyword">import</span> { ITask } <span class="hljs-keyword">from</span> <span class="hljs-string">"../models/interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getTasks = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { documents } = <span class="hljs-keyword">await</span> readDocuments();

    <span class="hljs-keyword">return</span> documents <span class="hljs-keyword">as</span> ITask[];
};
</code></pre>
<p>This defines the function and returns an array of <code>ITasks</code>. Go back to the <strong>Task.tsx</strong> file and fix any import errors. </p>
<p>Run the application and you should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-09-at-00.10.56.png" alt="Image" width="600" height="400" loading="lazy">
<em>your pending and completed tasks displayed in the browser</em></p>
<p>The task can be deleted or marked as complete but you won't see an update on the UI until the page is refreshed. To fix that, go back to the <strong>TaskItem</strong> file and paste the following code below the <code>isDone</code> useState and above the <code>handleDelete</code> function:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [isDone, setIsDone] = useState(<span class="hljs-literal">false</span>);

<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> updateTasks = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> allTasks = <span class="hljs-keyword">await</span> getTasks();
        <span class="hljs-keyword">if</span> (setTasks) setTasks(allTasks.reverse());
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
    }
};

<span class="hljs-comment">//rest of code below remains as is</span>
<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-keyword">async</span> (
</code></pre>
<p>Update <code>TaskItem</code> props interface and the <code>TaskItem</code> function like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">interface</span> TaskItemProps {
    task: ITask;
    setTasks?: <span class="hljs-function">(<span class="hljs-params">tasks: ITask[]</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskItem</span>(<span class="hljs-params">{ task, setTasks }: TaskItemProps</span>) </span>{
<span class="hljs-comment">//rest of code below</span>
    <span class="hljs-keyword">const</span> [isDone, setIsDone] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>This gives a setter function that resets the tasks array as a prop to the <code>TaskItem</code> component. </p>
<p>Adjust the <code>handleDelete</code> and <code>handleCheckbox</code> functions in the <code>TaskItem</code> component to include the <code>updateTasks</code> function you added above. it should read like this:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-keyword">async</span> (
    e: React.MouseEvent&lt;HTMLButtonElement&gt;,
    currentTaskId: <span class="hljs-built_in">string</span>
) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> deleteDocument(currentTaskId);
        updateTasks();
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
    }
};

<span class="hljs-keyword">const</span> handleCheckbox = <span class="hljs-keyword">async</span> (
    currentTask: IPayload,
    id: <span class="hljs-built_in">string</span>,
    e: React.ChangeEvent&lt;HTMLInputElement&gt;
    ) =&gt; {

    <span class="hljs-keyword">const</span> payload: IPayload = {
        title: currentTask.title,
        description: currentTask.description,
        due_date: currentTask.due_date,
        priority: currentTask.priority,
        done: e.target.checked,
    };

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> updateDocument(payload, id);
        updateTasks();
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
    }
};
</code></pre>
<p>Go back to the <strong>Task.tsx</strong> file and pass <code>setTasks</code> to the <code>TaskItem</code> component like so: <code>&lt;TaskItem key={task.$id} task={task} setTasks={setTasks} /&gt;</code>. Now, the UI updates without needing to manually refresh the page.</p>
<h3 id="heading-how-to-make-the-tasks-editable">How to Make the Tasks Editable</h3>
<p>In order to edit a task, you will need to pass a function to the edit button in the <code>TaskItem</code> component. </p>
<p>Paste the following code in the <strong>TaskItem.tsx</strong> file between the <code>updateTasks</code> and <code>handleDelete</code> functions like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-comment">//paste below updateTasks</span>
<span class="hljs-keyword">const</span> handleEdit = <span class="hljs-keyword">async</span> (
    currentTask: ITask
) =&gt; {
    navigate(<span class="hljs-string">"/"</span>, { state: { task: currentTask } });
};

<span class="hljs-comment">//rest of code untouched below</span>
</code></pre>
<p>Add this line right above the <code>isDone</code> useState: <code>const navigate = useNavigate();</code>. </p>
<p>In the same file, find the edit button and pass the <code>handleEdit</code> function to it. Also, wrap it in a condition that checks if the task is done such that the button is only displayed in the case that the task is not marked as complete. Like so:</p>
<pre><code class="lang-typescript">{!task.done &amp;&amp; (
    &lt;Button
        handleClick={<span class="hljs-function">() =&gt;</span> handleEdit(task)}
        extraBtnClasses=<span class="hljs-string">"bg-ok"</span>
    &gt;
        &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Edit&lt;/span&gt;
        &lt;PencilSquareIcon height={<span class="hljs-number">25</span>} className=<span class="hljs-string">"hidden lg:flex"</span> /&gt;
    &lt;/Button&gt;
)
</code></pre>
<p>The <code>AddTask</code> component has to be adjusted to handle editing a task and the <strong>Index.tsx</strong> file needs to be updated to handle the task to be edited being passed to it via the navigate <code>handleEdit</code> function.</p>
<p>First, go to the <strong>AddTask</strong> file and add some prop definitions directly below the import statements, then pass the new props to the component like so:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span>....

<span class="hljs-comment">// pass a task and an isEdit boolean</span>
<span class="hljs-comment">// if isEdit is true, then the form will be populated with the task's data</span>
<span class="hljs-keyword">interface</span> ITaskFormProps {
    task: ITask | <span class="hljs-literal">null</span>;
    isEdit?: <span class="hljs-built_in">boolean</span>;
    setTasks?: <span class="hljs-function">(<span class="hljs-params">tasks: ITask[]</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-comment">//pass component props</span>
<span class="hljs-keyword">const</span> AddTask = <span class="hljs-function">(<span class="hljs-params">{ task, isEdit, setTasks }: ITaskFormProps</span>) =&gt;</span> {
<span class="hljs-comment">//code untouched below</span>
</code></pre>
<p>Adjust the due date and priority useStates to read like below:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [dueDate, setDueDate] = useState(
    isEdit &amp;&amp; task?.due_date ? <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(task.due_date) : <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
);

<span class="hljs-keyword">const</span> [priority, setPriority] = useState(
    isEdit &amp;&amp; task?.priority ? task?.priority : priorityArray[<span class="hljs-number">0</span>]
);
</code></pre>
<p>Add a useEffect below the useStates like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [titleValidationError, setTitleValidationError] = useState(<span class="hljs-string">""</span>);

<span class="hljs-comment">//paste below useState statements</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isEdit &amp;&amp; task) {
        setTitleVal(task.title);
        setTextAreaVal(task.description);
    } <span class="hljs-keyword">else</span> {
        setTitleVal(<span class="hljs-string">""</span>);
    }
}, [isEdit, task]);
</code></pre>
<p>In the <code>handleSubmit</code> function within the same <strong>AddTask</strong> file, delete this line: <code>await createDocument(payload);</code> and replace with the below:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">if</span> (isEdit &amp;&amp; task) {
    <span class="hljs-keyword">await</span> updateDocument(payload, task!.$id);
    <span class="hljs-keyword">const</span> allTasks = <span class="hljs-keyword">await</span> getTasks();
    <span class="hljs-keyword">if</span> (setTasks) <span class="hljs-keyword">return</span> setTasks(allTasks.reverse());
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">await</span> createDocument(payload);
}
</code></pre>
<p>Now replace the <code>Button</code> component at the bottom of the file just above the form closing tag with this:</p>
<pre><code class="lang-typescript">
&lt;Button
    <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>
    disable={isSubmitting}
    extraBtnClasses=<span class="hljs-string">"bg-primary justify-center text-white font-semibold px-4 py-2 outline-1 hover:bg-primaryHover focus:ring-1 focus:ring-pink-800 w-full"</span>
&gt;
    &lt;span&gt;
        {isSubmitting ? <span class="hljs-string">"Submitting..."</span> : task ? <span class="hljs-string">"Edit Task"</span> : <span class="hljs-string">"Add Task"</span>}
    &lt;/span&gt;
&lt;/Button&gt;
<span class="hljs-comment">//unchanged code below</span>
&lt;/form&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddTask;
</code></pre>
<p>This sets the text on the button depending on whether the form is submitting, creating a new task or updating an exisiting task.</p>
<p>Go to the <strong>Index.tsx</strong> file in the <strong>routes</strong> folder and paste the following above the <code>return</code> statement:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">//paste here</span>
    <span class="hljs-keyword">const</span> location = useLocation();
    <span class="hljs-keyword">const</span> navigate = useNavigate();

    <span class="hljs-keyword">const</span> taskFromState: ITask = location.state?.task;

    <span class="hljs-keyword">const</span> [taskToEdit] = useState&lt;ITask | <span class="hljs-literal">null</span>&gt;(taskFromState ?? <span class="hljs-literal">null</span>);

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (taskFromState) {
            navigate(location.pathname, {});
        }
    }, [taskFromState, location.pathname, navigate]);

    <span class="hljs-comment">//below code remains unchanged</span>
    <span class="hljs-keyword">return</span> (....
</code></pre>
<p>Here, the file gets the task passed to it from the "/tasks" route and sets it to local state. Then the useEffect nullies the passed task so that the form is reset on refresh.</p>
<p>In the <strong>Index.tsx</strong> file replace the <code>AddTask</code> component with this line: <code>&lt;AddTask task={taskToEdit} isEdit={taskToEdit ? true : false} /&gt;</code>.</p>
<p>Run your application and you should be able to click on the edit button, be navigated back to the "/" route, have the form pre-filled with the task details, be able to edit some of the fields and be redirected back to "/tasks" once you click on the "Edit Task" button. </p>
<h3 id="heading-how-to-enable-viewing-of-tasks">How to Enable Viewing of Tasks</h3>
<p>The application now creates, reads, updates and deletes tasks. All that is left on that is the ability to view a particular task. </p>
<p>Go to the <strong>TaskItem</strong> file, add the following to the interface <code>TaskItemProps</code>: <code>isViewTask: boolean;    handleViewTask?: (e: React.MouseEvent&lt;HTMLDivElement&gt;) =&gt; void;</code>.</p>
<p>Add them as props to the <code>TaskItem</code> component and set <code>isViewTask</code> to a default of <code>false</code> like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskItem</span>(<span class="hljs-params">{
    task,
    setTasks,
    isViewTask = <span class="hljs-literal">false</span>,
    handleViewTask,
}: TaskItemProps</span>) </span>{    
    <span class="hljs-comment">//rest of code below unchanged</span>
    <span class="hljs-keyword">const</span> navigate = useNavigate();
</code></pre>
<p>Replace the paragraph tag that displays the task description within the <code>return</code> of the component with this markup:</p>
<pre><code class="lang-typescript">
&lt;p className=<span class="hljs-string">"py-1 mb-4 min-h-16 break-words"</span>&gt;
    {task.description.length &gt; <span class="hljs-number">70</span> &amp;&amp; !isViewTask
        ? task.description.substring(<span class="hljs-number">0</span>, <span class="hljs-number">70</span>) + <span class="hljs-string">"..."</span>
        : task.description
    }
&lt;/p&gt;
</code></pre>
<p>The change introduced will ensure that the full description is visible if <code>isViewTask</code> is set to <code>true</code>.</p>
<p>On the <code>div</code> tag just below the <code>return</code> in the same component, add an <code>onClick</code> handler like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">return</span> (
&lt;&gt;
    &lt;div
        className=<span class="hljs-string">"m-8 cursor-pointer border border-container rounded-md p-4                        hover:shadow-lg transition duration-300 ease-in-out max-h-                       96"</span>
        onClick={handleViewTask}
    &gt;
<span class="hljs-comment">//rest unchanged code</span>
...
</code></pre>
<p>Back in the <strong>Task.tsx</strong> file, paste the following just above the useEffect:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> handleViewTask = <span class="hljs-function">(<span class="hljs-params">
    e: React.MouseEvent&lt;HTMLDivElement&gt;,
    activeTask: ITask
</span>) =&gt;</span> {
    setIsViewTask(<span class="hljs-literal">true</span>);
    setSelectedTask(activeTask);
};

<span class="hljs-comment">//unchanged code below</span>
useEffect(...
</code></pre>
<p>Add the following useState functions above the <code>handleViewTask</code> function, below the other useStates:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [tasksError, setTasksError] = useState(<span class="hljs-string">""</span>);
<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> [isViewTask, setIsViewTask] = useState(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> [selectedTask, setSelectedTask] = useState&lt;ITask&gt;();

<span class="hljs-comment">//code below unchanged</span>
<span class="hljs-keyword">const</span> handleViewTask = (...
</code></pre>
<p>Now paste the following code within the <code>return</code> statement in the same file, just above the <code>h1</code> tag displaying "Your Tasks" text:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">return</span> (
&lt;main className=<span class="hljs-string">"container mx-auto"</span>&gt;
    &lt;section className=<span class="hljs-string">"max-w-5xl mx-auto m-12 p-16"</span>&gt;
        <span class="hljs-comment">//paste here</span>
        {isViewTask &amp;&amp; selectedTask &amp;&amp; (
            &lt;Dialog key={selectedTask.$id} setIsViewTask={setIsViewTask}&gt;
                &lt;TaskItem
                    task={selectedTask}
                    handleViewTask={<span class="hljs-function">() =&gt;</span> handleViewTask(selectedTask!)}
                    isViewTask={isViewTask}
                /&gt;
            &lt;/Dialog&gt;
        )}
        &lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
        Your Tasks
        &lt;/h1&gt;
        <span class="hljs-comment">//rest of code below remains unchanged</span>
</code></pre>
<p>You will need to create the Dialog component. Create a new file in the components folder and call it <strong>Dialog.tsx</strong>, then paste the following in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { XMarkIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/24/solid"</span>;
<span class="hljs-keyword">import</span> { ReactNode, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { ITask } <span class="hljs-keyword">from</span> <span class="hljs-string">"../models/interface"</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./Button"</span>;

<span class="hljs-keyword">interface</span> DialogProps {
    setIsViewTask?: <span class="hljs-function">(<span class="hljs-params">isViewTask: <span class="hljs-built_in">boolean</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
    children: ReactNode;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dialog</span>(<span class="hljs-params">{ setIsViewTask, children }: DialogProps</span>) </span>{
    <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">const</span> closeModal = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (setIsViewTask) setIsViewTask(<span class="hljs-literal">false</span>);
        setIsOpen(<span class="hljs-literal">false</span>);
    };
    <span class="hljs-keyword">return</span> (
        &lt;dialog
            open={isOpen}
            id=<span class="hljs-string">"modal"</span>
            style={{
            backgroundColor: <span class="hljs-string">"var(--base-bg)"</span>,
            color: <span class="hljs-string">"var(--text-main)"</span>,
            }}
            className={<span class="hljs-string">`<span class="hljs-subst">${
                isOpen ? <span class="hljs-string">"opacity-100"</span> : <span class="hljs-string">"opacity-0 pointer-events-none"</span>
                }</span> transition-opacity duration-300 ease-in-out fixed inset-0                      backdrop-filter backdrop-blur-md backdrop-brightness-50 w-4/6                      border border-container rounded-md max-h-[80vh] overflow-y-auto                 text-main`</span>}
        &gt;
        &lt;Button
            handleClick={closeModal}
            content={{ text: <span class="hljs-string">"Close"</span>, icon: XMarkIcon }}
            extraBtnClasses=<span class="hljs-string">"ml-auto text-main font-medium hover:text-error"</span>
        /&gt;
        &lt;div className=<span class="hljs-string">"max-h-[80vh] overflow-y-auto"</span>&gt;{children}&lt;/div&gt;
        &lt;/dialog&gt;
    );
    }

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Dialog;
</code></pre>
<p>Here, the file defined a <code>Dialog</code> component that takes in some props, displays a button and the children it receives from props. </p>
<p>Finally, replace the two <code>TaskItem</code> components in the <code>tasks.filter...</code> function within the return statement of the <strong>Task.tsx</strong> file with the following:</p>
<pre><code class="lang-typescript">
{tasks
    .filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> !task.done)
    .map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> (
        &lt;TaskItem
            key={task.$id}
            task={task}
            setTasks={setTasks}
            handleViewTask={<span class="hljs-function">() =&gt;</span> handleViewTask(task)}
            isViewTask={isViewTask}
        /&gt;
))}
</code></pre>
<p>You should be able to click on the task items and have the dialog pop up with the details of the task. </p>
<p>However, if you try to delete the item you will notice that it opens the dialog while deleting it. To fix that, adjust the <code>handleDelete</code> function in the <strong>TaskItem.tsx</strong> file to read like this: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-keyword">async</span> (
    e: React.MouseEvent&lt;HTMLButtonElement&gt;,
    currentTaskId: <span class="hljs-built_in">string</span>
) =&gt; {
    e.stopPropagation();
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> deleteDocument(currentTaskId);
        <span class="hljs-keyword">if</span> (isViewTask) {
            navigate(<span class="hljs-number">0</span>);
        } <span class="hljs-keyword">else</span> {
            updateTasks();
        }
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(error);
    }
};
</code></pre>
<p>You've added <code>e.stopPropagation()</code> to stop the event from bubbling up to the parent and potentially interfering with the click to open the dialog. </p>
<p>You've also added a check after deleting the task to see if the task is being viewed, in which case we refresh the page via the <code>navigate(0)</code> to force the UI to update to the proper state. If not, it proceeds to call <code>updateTasks()</code> to refresh the state.</p>
<p>You will notice the same issue when you try to mark the task as complete in which the dialog pops up. To fix this, adjust the checkbox input to include this line: <code>onClick={(e) =&gt; e.stopPropagation()}</code>. </p>
<p>The new line stops the event from bubbling up to the parent <code>div</code>. It is added to the <code>onClick</code> instead of the <code>onChange</code> because the event it is trying to intercept is of type <code>onClick</code>. The input should read like this:</p>
<pre><code class="lang-typescript">
&lt;label htmlFor=<span class="hljs-string">"done"</span> className=<span class="hljs-string">"mr-2 font-light"</span>&gt;
    Mark <span class="hljs-keyword">as</span> complete
&lt;/label&gt;
&lt;input
    <span class="hljs-keyword">type</span>=<span class="hljs-string">"checkbox"</span>
    checked={isDone}
    onClick={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> e.stopPropagation()}
    onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setIsDone(e.target.checked);
    handleCheckbox(task, task.$id, e);
    }}
    className=<span class="hljs-string">"size-5 accent-pink-600 rounded-sm"</span>
/&gt;
</code></pre>
<p>At this point, the React application is responsive, can CRUD the Appwrite database and the user can view individual tasks. </p>
<h3 id="heading-how-to-auto-generate-descriptions-with-vercels-ai-sdk">How to Auto Generate Descriptions with Vercel's AI SDK</h3>
<p>To enhance the application and its' user experience, you can add the ability to auto generate descriptions for the tasks using AI. </p>
<p>To get started, open an integrated terminal and run the following command: <code>npm i ai</code>. This adds the <a target="_blank" href="https://vercel.com/blog/introducing-the-vercel-ai-sdk">Vercel AI SDK</a> to the React application. </p>
<p>Next, run this command in the terminal: <code>npm i @huggingface/inference</code> to add Hugging Face support. The application will use <a target="_blank" href="https://sdk.vercel.ai/docs/guides/providers/huggingface">Hugging Face</a> because you need to pay to get programmatic access to OpenAI.</p>
<p>Create a new file in the utils folder, call it <strong>ai.ts</strong> and paste the following in it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { HfInference } <span class="hljs-keyword">from</span> <span class="hljs-string">"@huggingface/inference"</span>;
<span class="hljs-keyword">import</span> { HuggingFaceStream, StreamingTextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"ai"</span>;

<span class="hljs-comment">// Create a new HuggingFace Inference instance</span>
<span class="hljs-keyword">const</span> Hf = <span class="hljs-keyword">new</span> HfInference(<span class="hljs-keyword">import</span>.meta.env.VITE_HUGGINGFACE_KEY);

<span class="hljs-comment">// IMPORTANT! Set the runtime to edge</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> runtime = <span class="hljs-string">"edge"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> callAI = <span class="hljs-keyword">async</span> (prompt: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">const</span> response = Hf.textGenerationStream({
        model: <span class="hljs-string">"OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5"</span>,
        inputs: <span class="hljs-string">`&lt;|prompter|&gt;<span class="hljs-subst">${prompt}</span>&lt;|endoftext|&gt;&lt;|assistant|&gt;`</span>,
        parameters: {
            max_new_tokens: <span class="hljs-number">150</span>,
            <span class="hljs-comment">// @ts-ignore</span>
            typical_p: <span class="hljs-number">0.2</span>,
            repetition_penalty: <span class="hljs-number">1</span>,
            truncate: <span class="hljs-number">1000</span>,
            return_full_text: <span class="hljs-literal">false</span>,
        },
    });

    <span class="hljs-comment">// Convert the response into a friendly text-stream</span>
    <span class="hljs-keyword">const</span> stream = HuggingFaceStream(response);

    <span class="hljs-comment">// Respond with the stream</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StreamingTextResponse(stream);
};
</code></pre>
<p>This boilerplate creates an instance of Hugging Face, creates a function that takes in a prompt, passes that prompt to the <code>textGenerationStream</code> function. Then it converts the response to a stream and to a text stream. </p>
<p>You will need to add a Hugging Face access token. You can genrate one at this <a target="_blank" href="https://huggingface.co/settings/tokens">address</a>. You will need an account before you can access it. </p>
<p>Once you have token, open the env file and add to it the following line</p>
<pre><code class="lang-env">
//replace with your actual token
VITE_HUGGINGFACE_KEY=YOUR-HF-ACCESS-TOKEN
</code></pre>
<p>Open the <strong>AddTask.tsx</strong> file and paste the following button just above the closing div tag of the <code>div</code> containing the textarea input:</p>
<pre><code class="lang-typescript">
{textAreaVal.length &gt; <span class="hljs-number">197</span> &amp;&amp; (
    &lt;span className=<span class="hljs-string">"text-error mt-1"</span>&gt;
        Warning description getting too long. Can only be <span class="hljs-number">200</span> characters
    &lt;/span&gt;
)}
<span class="hljs-comment">//paste here</span>
&lt;Button
    handleClick={generateDesc}
    disable={isGenerating}
    extraBtnClasses=<span class="hljs-string">"bg-light mt-2 w-fit ml-auto"</span>
&gt;
    &lt;span&gt;Generate description&lt;/span&gt;
    &lt;SparklesIcon height={<span class="hljs-number">20</span>} /&gt;
&lt;/Button&gt;
<span class="hljs-comment">//rest of below code unchanged</span>
&lt;/div&gt;
</code></pre>
<p>Define <code>generateDesc</code> function just above the <code>return</code> statement in the <strong>AddTask</strong> file like so:</p>
<pre><code>
<span class="hljs-keyword">const</span> generateDesc = <span class="hljs-keyword">async</span> () =&gt; {
    setTextAreaVal(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">if</span> (!titleVal) {
    alert(<span class="hljs-string">"Please provide a title for the task"</span>);
    <span class="hljs-keyword">return</span>;
    }

    setIsGenerating(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">const</span> prompt = <span class="hljs-string">`Provide a description for this task: <span class="hljs-subst">${titleVal}</span>. Keep the description to a maximum of 30 words`</span>;

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> callAI(prompt);
        <span class="hljs-keyword">const</span> responseText = <span class="hljs-keyword">await</span> res.text();

        setIsGenerating(<span class="hljs-literal">false</span>);

        <span class="hljs-comment">//create a typing effect</span>
        responseText.split(<span class="hljs-string">""</span>).forEach(<span class="hljs-function">(<span class="hljs-params">char, index</span>) =&gt;</span> {
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        setTextAreaVal(<span class="hljs-function">(<span class="hljs-params">prevText</span>) =&gt;</span> prevText + char);
        }, index * <span class="hljs-number">32</span>);
        });
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ERROR HUGGING FACE API: "</span> + error);
    }
};
</code></pre><p>The function checks that the title is not empty and uses the title to create a prompt to pass on the Hugging Face helper. The response from the call is saved to local state. A simple typing effect is created as the textarea is populated with the response. </p>
<p>Next, add this useState: <code>const [isGenerating, setIsGenerating] = useState(false);</code> to the other useStates in the <code>AddTask</code> component.</p>
<p>Replace the textarea input in the same component with the following:</p>
<pre><code class="lang-typescript">
&lt;textarea
    id=<span class="hljs-string">"description"</span>
    placeholder=<span class="hljs-string">"Describe your task"</span>
    maxLength={<span class="hljs-number">200</span>}
    value={isGenerating ? <span class="hljs-string">"generating..."</span> : textAreaVal}
    onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setTextAreaVal(e.target.value)}
    className={<span class="hljs-string">`bg-inherit border rounded-sm p-2 h-32 resize-none          focus:outline-none focus:ring-1 <span class="hljs-subst">${
    textAreaVal.length &gt; <span class="hljs-number">197</span>
    ? <span class="hljs-string">"border-error focus:ring-red-500 invalid:focus:ring-red-600"</span>
    : <span class="hljs-string">"border-input focus:ring-slate-900"</span>
    }</span>`</span>}
/&gt;
</code></pre>
<p>On checking the application, you should see the button and be able to generate a description for the title of a task as below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-09-at-04.57.05.png" alt="Image" width="600" height="400" loading="lazy">
<em>ai-enhanced task description</em></p>
<h3 id="heading-voice-enable-the-application-with-the-react-speech-recognition-package">Voice-enable the Application with the React Speech Recognition Package</h3>
<p>First, you need to add the dependency and its Typescript helper by running the following commands in an integrated terminal window: <code>npm i react-speech-recognition</code> and <code>npm i @types/react-speech-recognition</code>. </p>
<p>Additionally, run the following command to get the dependency to work properly: <code>npm i regenerator-runtime</code>.</p>
<p>Create a <strong>hooks</strong> folder within the <strong>src</strong> folder. Create a file within it called <strong>useSpeechToTextHelper.ts</strong> and paste the following in it:</p>
<pre><code class="lang-typeacript">
import "regenerator-runtime/runtime";
import { useState } from "react";
import { useSpeechRecognition } from "react-speech-recognition";

export function useSpeechToTextHelper() {
    const [error, setError] = useState("");

    const {
        transcript,
        listening,
        resetTranscript,
        browserSupportsSpeechRecognition,
    } = useSpeechRecognition();

    if (!browserSupportsSpeechRecognition) {
        setError("Browser doesn't support speech recognition.");
    }

    return {
        error,
        listening,
        transcript,
        resetTranscript,
    };
}
</code></pre>
<p>This hook exposes some built in helper functions from React Speech Recognition, handles the case that the browser does not support the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition">relevant web APIs</a> and returns some of that data.</p>
<p>Create a new file in the components folder called <strong>Speaker.tsx</strong>. Paste the following code into it:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { useSpeechToTextHelper } <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useSpeechToTextHelper"</span>;
<span class="hljs-keyword">import</span> { MicrophoneIcon, XCircleIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@heroicons/react/24/solid"</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./Button"</span>;
<span class="hljs-keyword">import</span> SpeechRecognition <span class="hljs-keyword">from</span> <span class="hljs-string">"react-speech-recognition"</span>;

<span class="hljs-keyword">interface</span> SpeakerProps {
handleClear: <span class="hljs-function">(<span class="hljs-params">e: React.MouseEvent&lt;HTMLButtonElement&gt;</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Speaker</span>(<span class="hljs-params">{ handleClear }: SpeakerProps</span>) </span>{
    <span class="hljs-keyword">const</span> { listening, error } = useSpeechToTextHelper();

    <span class="hljs-keyword">const</span> handleSpeech = <span class="hljs-function">() =&gt;</span> {
        SpeechRecognition.startListening();
    };

    <span class="hljs-keyword">return</span> (
    &lt;div&gt;
        {error &amp;&amp; &lt;div&gt;{error}&lt;/div&gt;}
        &lt;div className=<span class="hljs-string">"flex gap-2 py-1 items-center text-center justify-center"</span>&gt;
            &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;{listening ? <span class="hljs-string">"Mic on"</span> : <span class="hljs-string">"Mic off"</span>}&lt;/span&gt;
            &lt;Button
                handleClick={handleSpeech}
                extraBtnClasses=<span class="hljs-string">"bg-lightOk"</span>
                title=<span class="hljs-string">"Start"</span>
            &gt;
                &lt;MicrophoneIcon height={<span class="hljs-number">25</span>} /&gt;
            &lt;/Button&gt;
            &lt;Button
                handleClick={handleClear}
                extraBtnClasses=<span class="hljs-string">"bg-light"</span>
                <span class="hljs-keyword">type</span>=<span class="hljs-string">"reset"</span>
                title=<span class="hljs-string">"Reset"</span>
            &gt;
                &lt;XCircleIcon height={<span class="hljs-number">25</span>} /&gt;
            &lt;/Button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Speaker;
</code></pre>
<p>This components accepts a function to clear the voice input as a prop, uses the helper hook, defines a function to handle the actual speech, handles potential error state and displays a button for handling the speech and another for clearing the voice transcript.</p>
<p>In the <strong>AddTask</strong> file, delete the label for title and replace it with the following markup:</p>
<pre><code class="lang-typescript">
&lt;div className=<span class="hljs-string">"flex flex-row justify-between items-center"</span>&gt;
    &lt;label htmlFor=<span class="hljs-string">"title"</span>&gt;Task Title&lt;/label&gt;
    &lt;Speaker handleClear={clearTranscript} /&gt;
&lt;/div&gt;
</code></pre>
<p>This adds the <code>Speaker</code> component and wraps both the label and the <code>Speaker</code> component in a representational <code>div</code> in order to maintain the form layout. </p>
<p>Add the <code>clearTranscript</code> function just above the <code>handleSubmit</code> function like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> handleTitleChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> {
    setTitleVal(e.target.value);

    <span class="hljs-keyword">if</span> (e.target.value.trim() !== <span class="hljs-string">""</span>) {
        setTitleValidationError(<span class="hljs-string">""</span>);
    }
};

<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> clearTranscript = <span class="hljs-function">() =&gt;</span> {
    resetTranscript();
};
<span class="hljs-comment">//below code is unchanged</span>
<span class="hljs-keyword">const</span> handleSubmitTask = asyc....
</code></pre>
<p>Next in the same <code>AddTask</code> component, add the following:</p>
<pre><code>
<span class="hljs-keyword">const</span> AddTask = <span class="hljs-function">(<span class="hljs-params">{ task, isEdit, setTasks }: ITaskFormProps</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> navigate = useNavigate();
    <span class="hljs-comment">//paste here</span>
    <span class="hljs-keyword">const</span> { transcript, resetTranscript } = useSpeechToTextHelper();
    <span class="hljs-comment">//rest remains unchanged</span>
</code></pre><p>Replace the useEffect in the file with this new one:</p>
<pre><code class="lang-typescript">
useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (isEdit &amp;&amp; task &amp;&amp; !transcript) {
        setTitleVal(task.title);
        setTextAreaVal(task.description);
    } <span class="hljs-keyword">else</span> {
        setTitleVal(transcript || <span class="hljs-string">""</span>);
    }
}, [isEdit, task, transcript]);
</code></pre>
<p>Your application should now support creating titles for the tasks via voice inputs. And should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-09-at-05.36.51.png" alt="Image" width="600" height="400" loading="lazy">
<em>voice input functionality added to the form</em></p>
<h3 id="heading-how-to-add-search-functionality-to-the-application">How to Add Search Functionality to the Application</h3>
<p>To increase ease of use, it is useful to have some search functionality in the application. </p>
<p>To start, open up the Appwrite console. Click into your collections, click on Indexes tab then click on the "Create index" button. </p>
<p>Leave the index key as is, select FullText in the index type dropdown. Add title attribute and create the index. Repeat the process for the description attribute.</p>
<p>In your application, open <strong>db.ts</strong> file in <strong>utils</strong> folder and paste the following function just above the <code>export</code> keyword, then add it to the list of exports:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> searchTasks = <span class="hljs-keyword">async</span> (searchTerm: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">const</span> resTitle = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID, [
                        Query.search(<span class="hljs-string">"title"</span>, searchTerm),
                    ]);
    <span class="hljs-keyword">const</span> resDesc = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID, [
                        Query.search(<span class="hljs-string">"description"</span>, searchTerm),
                     ]);
    <span class="hljs-keyword">const</span> res = [...resTitle.documents, ...resDesc.documents];

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

<span class="hljs-keyword">export</span> {
    createDocument,
    readDocuments,
    updateDocument,
    deleteDocument,
    searchTasks,
};
</code></pre>
<p>Create a new file in the components folder, calll it <strong>Search.tsx</strong>. Paste the following into it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { FormEvent, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { ITask } <span class="hljs-keyword">from</span> <span class="hljs-string">"../models/interface"</span>;
<span class="hljs-keyword">import</span> Dialog <span class="hljs-keyword">from</span> <span class="hljs-string">"./Dialog"</span>;
<span class="hljs-keyword">import</span> TaskItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./TaskItem"</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./Button"</span>;
<span class="hljs-keyword">import</span> { searchTasks } <span class="hljs-keyword">from</span> <span class="hljs-string">"../utils/db"</span>;

<span class="hljs-keyword">const</span> Search = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-keyword">const</span> [searchTerm, setSearchTerm] = useState(<span class="hljs-string">""</span>);
<span class="hljs-keyword">const</span> [isSearching, setIsSearching] = useState(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> [searchedTasks, setSearchedTasks] = useState&lt;ITask[]&gt;([]);
<span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">return</span> (
        &lt;div className=<span class="hljs-string">"flex flex-col w-full md:w-1/2"</span>&gt;
            &lt;form
                className=<span class="hljs-string">"flex flex-col md:flex-row items-start md:items-center gap-2"</span>
                onSubmit={handleSubmit}
            &gt;
                {searchedTasks.length &gt; <span class="hljs-number">0</span> &amp;&amp; (
                    &lt;Dialog setSearchedTasks={setSearchedTasks}&gt;
                        {searchedTasks.map(<span class="hljs-function">(<span class="hljs-params">task: ITask</span>) =&gt;</span> (
                            &lt;TaskItem key={task.$id} task={task} isViewTask={<span class="hljs-literal">true</span>} /&gt;
                        ))}
                    &lt;/Dialog&gt;
                )}
            &lt;input
                aria-roledescription=<span class="hljs-string">"search"</span>
                <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
                id=<span class="hljs-string">"search"</span>
                placeholder=<span class="hljs-string">"search your tasks..."</span>
                value={searchTerm}
                onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setSearchTerm(e.target.value)}
                className={<span class="hljs-string">`bg-inherit w-5/6 border rounded-md p-2 focus:outline-none focus:ring-1 <span class="hljs-subst">${
                error
                ? <span class="hljs-string">"border-error focus:ring-red-500 invalid:focus:ring-red-600"</span>
                : <span class="hljs-string">"border-input focus:ring-slate-900"</span>
                }</span>`</span>}
            /&gt;
            &lt;Button
            <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>
            extraBtnClasses=<span class="hljs-string">"bg-primary text-white hover:bg-primaryHover font-medium text-main py-2"</span>
            &gt;
                &lt;span&gt;{isSearching ? <span class="hljs-string">"Searching..."</span> : <span class="hljs-string">"Search"</span>}&lt;/span&gt;
            &lt;/Button&gt;
            &lt;/form&gt;
            &lt;span className=<span class="hljs-string">"text-error font-medium mt-1"</span>&gt;{error}&lt;/span&gt;
        &lt;/div&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Search;
</code></pre>
<p>The new <code>Search</code> component creates some local state and returns a form with an input and search button. It also opens the dialog when it has search results.</p>
<p>Add this <code>handleSubmit</code> function above the <code>return</code> statement like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e: FormEvent&lt;HTMLFormElement&gt;) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">if</span> (!searchTerm) {
        setError(<span class="hljs-string">"No search term entered"</span>);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        setError(<span class="hljs-string">""</span>);
        }, <span class="hljs-number">3000</span>);
        <span class="hljs-keyword">return</span>;
    }

    setIsSearching(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> searchTasks(searchTerm);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"res search: "</span>, res);
    <span class="hljs-keyword">if</span> (res.length === <span class="hljs-number">0</span>) {
        setIsSearching(<span class="hljs-literal">false</span>);
        setError(<span class="hljs-string">"No task found"</span>);
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        setSearchTerm(<span class="hljs-string">""</span>);
        setError(<span class="hljs-string">""</span>);
        }, <span class="hljs-number">3000</span>);
        <span class="hljs-keyword">return</span>;
    }
    setIsSearching(<span class="hljs-literal">false</span>);
    setSearchedTasks(res <span class="hljs-keyword">as</span> ITask[]);
};
</code></pre>
<p>This function sets an error if no search term is received, then it attempts to call the database search function passing it the search term. If successful it sets the tasks to local state and if not, it catches the error.</p>
<p>Click into the dialog component and replace its props with the following, then pass the <code>setSearchedTasks</code> to it like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">interface</span> DialogProps {
    setIsViewTask?: <span class="hljs-function">(<span class="hljs-params">isViewTask: <span class="hljs-built_in">boolean</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
    setSearchedTasks?: <span class="hljs-function">(<span class="hljs-params">tasks: ITask[]</span>) =&gt;</span> <span class="hljs-built_in">void</span>;
    children: ReactNode;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dialog</span>(<span class="hljs-params">{ setIsViewTask, setSearchedTasks, children }: DialogProps</span>) </span>{...
</code></pre>
<p>Replace the <code>closeModal</code> function in the dialog component with this snippet:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> closeModal = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (setIsViewTask) setIsViewTask(<span class="hljs-literal">false</span>);
    <span class="hljs-comment">//this is the new line</span>
    <span class="hljs-keyword">if</span> (setSearchedTasks) setSearchedTasks([]);
    setIsOpen(<span class="hljs-literal">false</span>);
};
</code></pre>
<p>Go back into the <strong>Task.tsx</strong> file and paste this below the <code>h1</code> tag that displays the "Your Tasks" text:</p>
<pre><code class="lang-typescript">
&lt;h1 className=<span class="hljs-string">"text-4xl md:text-7xl font-bold text-center py-3 mb-16"</span>&gt;
Your Tasks
&lt;/h1&gt;
<span class="hljs-comment">//paste here</span>
&lt;div className=<span class="hljs-string">"m-8 flex flex-col-reverse md:flex-row gap-8 items-start                     md:items-center md:justify-between"</span>&gt;
    &lt;Search /&gt;
    &lt;Button
        handleClick={<span class="hljs-function">() =&gt;</span> navigate(<span class="hljs-string">"/"</span>)}
        extraBtnClasses=<span class="hljs-string">"bg-primary text-white font-medium py-2 hover:bg-    primaryHover ml-auto"</span>
    &gt;
        &lt;span&gt;Add Task&lt;/span&gt;
        &lt;PlusIcon height={<span class="hljs-number">25</span>} className=<span class="hljs-string">"hidden md:flex"</span> /&gt;
    &lt;/Button&gt;
&lt;/div&gt;
<span class="hljs-comment">//rest of code stays unchanged</span>
</code></pre>
<p>This adds the search component and a button that takes you back to the Index page when clicked.</p>
<p>Add the following within the Task component just below the useStates:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> [selectedTask, setSelectedTask] = useState&lt;ITask&gt;();
<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> navigate = useNavigate();
<span class="hljs-comment">//all below remain unchanged</span>
<span class="hljs-keyword">const</span> handleSelectChange = (e: React.ChangeEvent&lt;HTMLSelectElement&gt;)
</code></pre>
<p>You can now test your search functionality. It works but has one bug: if the search term is present in the both the title and the description we get back two search results. </p>
<p>To fix that, modify the <code>searchTasks</code> function in <strong>db.ts</strong> to filter out duplicate tasks by IDs like so: </p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> searchTasks = <span class="hljs-keyword">async</span> (searchTerm: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">const</span> resTitle = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID, [
        Query.search(<span class="hljs-string">"title"</span>, searchTerm),
    ]);
    <span class="hljs-keyword">const</span> resDesc = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID, [
        Query.search(<span class="hljs-string">"description"</span>, searchTerm),
    ]);

    <span class="hljs-keyword">const</span> res = [...resTitle.documents, ...resDesc.documents];

    <span class="hljs-comment">// remove duplicate tasks</span>
    <span class="hljs-keyword">const</span> uniqueRes = res.filter(
        <span class="hljs-function">(<span class="hljs-params">task, index, self</span>) =&gt;</span> index === self.findIndex(<span class="hljs-function">(<span class="hljs-params">t</span>) =&gt;</span> t.$id ===                  task.$id)
    );

    <span class="hljs-keyword">return</span> uniqueRes;
};
</code></pre>
<p>Now your search should work as expected and should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-09-at-08.00.40.png" alt="Image" width="600" height="400" loading="lazy">
<em>your pending and completed tasks displayed in the browser</em></p>
<h3 id="heading-how-to-add-ability-to-sort-tasks-via-due-date-and-priority">How to Add Ability to Sort Tasks via Due Date and Priority</h3>
<p>The application will only sort the pending tasks as it makes the most sense. It will sort by due date from the earliest date to the latest and vice versa. It will also sort by priority from lowest to highest and vice versa.</p>
<p>To get started, paste the following in the <strong>Tasks.tsx</strong> file right below the <code>h3</code> tag with the "Pending Tasks" text like so:</p>
<pre><code class="lang-typescript">
&lt;h3 className=<span class="hljs-string">"text-2xl font-bold m-8"</span>&gt;Pending Tasks&lt;/h3&gt;
<span class="hljs-comment">//paste here</span>
&lt;div className=<span class="hljs-string">"m-8 flex items-start lg:items-center gap-1 justify-between flex-col lg:flex-row"</span>&gt;
    &lt;span className=<span class="hljs-string">"font-medium"</span>&gt;Sort Tasks by: &lt;/span&gt;
    &lt;Select
        defaultSelectValue={selectArray[<span class="hljs-number">0</span>]}
        handleSelectChange={handleSelectChange}
        selectOptions={selectArray}
    /&gt;
&lt;/div&gt;
</code></pre>
<p>Then paste the following array that will contain the options for select component above. Paste it right above <code>handleViewTask</code> function like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> navigate = useNavigate();
<span class="hljs-comment">//paste here</span>
<span class="hljs-keyword">const</span> selectArray = [
    <span class="hljs-string">"priority - (low - high)"</span>,
    <span class="hljs-string">"priority - (high - low)"</span>,
    <span class="hljs-string">"due date - (earliest - latest)"</span>,
    <span class="hljs-string">"due date - (latest - earliest)"</span>,
];
<span class="hljs-comment">//rest remains unchanged</span>
<span class="hljs-keyword">const</span> handleViewTask = (...
</code></pre>
<p>Add the <code>handleSelectChange</code> and the sort functions above the <code>selectArray</code>, like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> sortByPriority = (tasksList: ITask[], isAsc: <span class="hljs-built_in">boolean</span>): ITask[] =&gt; {
    <span class="hljs-keyword">const</span> priorityOrder: { [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">number</span> } = {
    low: <span class="hljs-number">1</span>,
    medium: <span class="hljs-number">2</span>,
    high: <span class="hljs-number">3</span>,
    };

    <span class="hljs-keyword">return</span> [...tasksList].sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> priorityA = priorityOrder[a.priority!.toLowerCase()];
    <span class="hljs-keyword">const</span> priorityB = priorityOrder[b.priority!.toLowerCase()];
    <span class="hljs-keyword">return</span> isAsc ? priorityA - priorityB : priorityB - priorityA;
    });
};

<span class="hljs-keyword">const</span> handleSelectChange = <span class="hljs-keyword">async</span> (
    e: React.ChangeEvent&lt;HTMLSelectElement&gt;
) =&gt; {
    <span class="hljs-keyword">const</span> selectedOption = e.target.value;
    <span class="hljs-keyword">const</span> doneTasks = tasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task.done);

    <span class="hljs-keyword">switch</span> (selectedOption) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">"priority - (low - high)"</span>:
        <span class="hljs-keyword">case</span> <span class="hljs-string">"priority - (high - low)"</span>: {
            <span class="hljs-keyword">const</span> isAsc = selectedOption === <span class="hljs-string">"priority - (low - high)"</span>;
            <span class="hljs-keyword">const</span> sortedTasks = sortByPriority(tasks, isAsc);
            setTasks([...doneTasks, ...sortedTasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>                           !task.done)]);
            <span class="hljs-keyword">break</span>;
        }
        <span class="hljs-keyword">case</span> <span class="hljs-string">"due date - (earliest - latest)"</span>:
        <span class="hljs-keyword">case</span> <span class="hljs-string">"due date - (latest - earliest)"</span>: {
            <span class="hljs-keyword">const</span> isEarliestToLatest =
            selectedOption === <span class="hljs-string">"due date - (earliest - latest)"</span>;
            <span class="hljs-keyword">const</span> dueDateResult = <span class="hljs-keyword">await</span> sortByDueDate(isEarliestToLatest);
            <span class="hljs-keyword">const</span> sortedTasks = dueDateResult.documents <span class="hljs-keyword">as</span> ITask[];
            setTasks([...doneTasks, ...sortedTasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>                            !task.done)]);
            <span class="hljs-keyword">break</span>;
        }
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">break</span>;
        }
};

<span class="hljs-comment">//below remains unchanged</span>
<span class="hljs-keyword">const</span> selectArray = .....
</code></pre>
<p>The sortByPriority function creates an object whose keys map to the priority array and gives them numerical values. This makes it easier to sort as it is hard to tell which string is higher priority without that.</p>
<p>The <code>handleSelectChange</code> function picks out the selected option and filters the tasks to get the completed ones. It does matching logic in the switch statements, calling <code>sortByPriority</code> for the cases where the user is trying to do that and it calls <code>sortByDueDate</code> for the rest of the cases. </p>
<p><code>sortByDueDate</code> is defined in the <strong>db.ts</strong> file. Open it and paste the following at the bottom of the file above the exports. Then add it to the exports list like so:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> sortByDueDate = <span class="hljs-keyword">async</span> (isEarliestToLatest: <span class="hljs-built_in">boolean</span>) =&gt; {
    <span class="hljs-keyword">const</span> orderQuery = isEarliestToLatest
        ? Query.orderAsc(<span class="hljs-string">"due_date"</span>)
        : Query.orderDesc(<span class="hljs-string">"due_date"</span>);
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> databases.listDocuments(dbID, collectionID,              [orderQuery]);
    <span class="hljs-keyword">return</span> res;
};

<span class="hljs-keyword">export</span> {
    createDocument,
    readDocuments,
    updateDocument,
    deleteDocument,
    searchTasks,
    sortByDueDate,
};
</code></pre>
<p>This function leverages Appwrites' Query methods to sort the date string according to the Boolean that is passed to it.</p>
<p>Going back to your application, run it to test the sorting functionality. The application should be sorted and the sorting should only apply to the pending tasks.</p>
<h3 id="heading-bonus-how-to-add-dark-mode-support">Bonus: How to Add Dark Mode Support</h3>
<p>The last thing left is to add Dark Mode support that respects the users' systems setting. </p>
<p>For this, open the <strong>tailwind.config.ts</strong> file and replace its contents with the following:</p>
<pre><code class="lang-typescript">
<span class="hljs-comment">/** @type {import('tailwindcss').Config} */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    content: [<span class="hljs-string">"./index.html"</span>, <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>],
    darkMode: <span class="hljs-string">"selector"</span>,
    theme: {
        extend: {
            textColor: {
                error: <span class="hljs-string">"var(--text-error)"</span>,
                ok: <span class="hljs-string">"var(--text-ok)"</span>,
                main: <span class="hljs-string">"var(--text-main)"</span>,
                iconColor: <span class="hljs-string">"var(--btn-icon-main)"</span>,
            },
            backgroundColor: {
                base: <span class="hljs-string">"var(--base-bg)"</span>,
                primary: <span class="hljs-string">"var(--btn-bg-primary)"</span>,
                primaryHover: <span class="hljs-string">"var(--btn-bg-primary-hover)"</span>,
                ok: <span class="hljs-string">"var(--btn-bg-ok)"</span>,
                lightOk: <span class="hljs-string">"var(--btn-bg-light-ok)"</span>,
                light: <span class="hljs-string">"var(--btn-bg-light)"</span>,
                lowPriority: <span class="hljs-string">"var(--low-priority)"</span>,
                mediumPriority: <span class="hljs-string">"var(--medium-priority)"</span>,
                highPriority: <span class="hljs-string">"var(--high-priority)"</span>,
            },
            borderColor: {
                container: <span class="hljs-string">"var(--border-container)"</span>,
                input: <span class="hljs-string">"var(--border-input)"</span>,
                error: <span class="hljs-string">"var(--border-error)"</span>,
            },
        },
    },
    plugins: [],
};
</code></pre>
<p>This extends the tailwind preset colors and ties the CSS variables that were set in the <strong>index.css</strong> file to the Tailwind config. </p>
<p>In the <strong>index.css</strong> file, add this dark class below the date class like so:</p>
<pre><code class="lang-css">
<span class="hljs-selector-id">#date</span><span class="hljs-selector-pseudo">::-webkit-calendar-picker-indicator</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--btn-bg-light); 
}
//<span class="hljs-selector-tag">paste</span> <span class="hljs-selector-tag">here</span>
<span class="hljs-selector-class">.dark</span>{
    <span class="hljs-attribute">--base-bg</span>: <span class="hljs-number">#262626</span>;
    <span class="hljs-attribute">--text-main</span>: <span class="hljs-number">#ffffff</span>;
    <span class="hljs-attribute">--text-error</span>: <span class="hljs-number">#fca5a5</span>;
    <span class="hljs-attribute">--text-ok</span>: <span class="hljs-number">#86efac</span>;
    <span class="hljs-attribute">--border-input</span>: <span class="hljs-number">#e2e8f0</span>;
    <span class="hljs-attribute">--border-error</span>: <span class="hljs-number">#fca5a5</span>;
}
</code></pre>
<p>This changes some of the CSS variables values when the dark class is applied.</p>
<p>Now, open the navbar file in the components folder and replace its contents with the following:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> navigate = useNavigate();

    <span class="hljs-keyword">const</span> themeArray = [<span class="hljs-string">"light"</span>, <span class="hljs-string">"dark"</span>, <span class="hljs-string">"system"</span>];
    <span class="hljs-keyword">const</span> [theme, setTheme] = useState(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"theme"</span>) || themeArray[<span class="hljs-number">2</span>];
    });

    <span class="hljs-keyword">const</span> applyTheme = <span class="hljs-function">(<span class="hljs-params">selectedTheme: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> isDarkModePreferred = <span class="hljs-built_in">window</span>.matchMedia(
            <span class="hljs-string">"(prefers-color-scheme: dark)"</span>
            ).matches;

        <span class="hljs-built_in">document</span>.documentElement.classList.remove(<span class="hljs-string">"light"</span>, <span class="hljs-string">"dark"</span>);
        <span class="hljs-built_in">document</span>.documentElement.classList.add(selectedTheme);

        <span class="hljs-keyword">if</span> (selectedTheme === <span class="hljs-string">"system"</span>) {
        <span class="hljs-built_in">document</span>.documentElement.classList.toggle(<span class="hljs-string">"dark"</span>, isDarkModePreferred);
        <span class="hljs-built_in">document</span>.documentElement.classList.toggle(<span class="hljs-string">"light"</span>,                  !isDarkModePreferred);
        }
    };

    <span class="hljs-keyword">const</span> handleSelectTheme = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLSelectElement&gt;</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> selectedTheme = e.target.value;
        setTheme(selectedTheme);

        <span class="hljs-comment">// Store the selected theme in localStorage</span>
        <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"theme"</span>, selectedTheme);
    };

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

    <span class="hljs-keyword">return</span> (
        &lt;nav className=<span class="hljs-string">"py-4 border-b-2 border-container shadow-md shadow-gray-400 w-full fixed top-0 bg-base"</span>&gt;
            &lt;ul className=<span class="hljs-string">"flex items-center justify-between  w-11/12 mx-auto"</span>&gt;
                &lt;Link to=<span class="hljs-string">"/"</span>&gt;
                    &lt;Button&gt;
                        &lt;span className=<span class="hljs-string">"font-semibold text-main"</span>&gt;Taskwrite&lt;/span&gt;
                        &lt;PencilIcon height={<span class="hljs-number">20</span>} className=<span class="hljs-string">"text-main"</span> /&gt;
                    &lt;/Button&gt;
                &lt;/Link&gt;
                &lt;div className=<span class="hljs-string">"flex items-center justify-between gap-6"</span>&gt;
                &lt;Link
                    to=<span class="hljs-string">"/tasks"</span>
                    className=<span class="hljs-string">"font-semibold hover:scale-105 transition duration-300 ease-in-out"</span>
                &gt;
                    View Tasks
                &lt;/Link&gt;
                &lt;div className=<span class="hljs-string">"flex gap-2 items-center"</span>&gt;
                    &lt;span className=<span class="hljs-string">"font-semibold"</span>&gt; Theme: &lt;/span&gt;
                    &lt;Select
                        defaultSelectValue={theme}
                        selectOptions={themeArray}
                        handleSelectChange={handleSelectTheme}
                    /&gt;
                &lt;/div&gt;
                &lt;/div&gt;
            &lt;/ul&gt;
        &lt;/nav&gt;
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>Your application should now have a select in the navigation menu that successfully toggles between dark and light themes while defaulting to the system preferences when set to "System". </p>
<p>It should look like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Screenshot-2024-03-09-at-13.21.38.png" alt="Image" width="600" height="400" loading="lazy">
<em>Taskwrite complete interface and functionalities</em></p>
<p>And Taskwrite is complete! You have successfully built a task manager application that is AI-enhanced, voice-enabled, searchable and sortable using React and Appwrite.</p>
<h2 id="heading-notes">Notes</h2>
<p>Appwrite recently announced some new features that would greatly simplify the search functionality above but, at the time of writing, these changes were not rolled out to their cloud offering. </p>
<p>The application could be further simplified by using state management solutions and this will be added to it in subsequent articles.</p>
<p>The application is live <a target="_blank" href="https://taskwrite.netlify.app/">here</a>.</p>
<h2 id="heading-limitations">Limitations</h2>
<p>The following are some known limitations and issues with this application:</p>
<ul>
<li>The navigation menu is not responsive</li>
<li>The application has no tests written</li>
<li>The permissions set for Appwrite are permissive and not recommended for production environments</li>
<li>The application could leverage <a target="_blank" href="https://appwrite.io/docs/apis/realtime">Appwrites' Realtime</a> capabilites for a smoother experience</li>
<li>The application could do with push notifications to remind the user when the task due date is coming up</li>
</ul>
<p>That said, the application is going to continue being improved and worked on. You can follow along with that on <a target="_blank" href="https://github.com/FatumaA/taskwrite">GitHub</a>. All contributions and improvements on the codebase are welcome. Please star the repository while you are at it.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a CRUD API – NodeJS and Express Project for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ An API is a technology that powers communication between software applications on the internet. API stands for Application Programming Interface, and it is basically a set of rules and protocols that define how different software can interact with ea... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-crud-api-project/</link>
                <guid isPermaLink="false">66ba305cf1ac6be9964fe7ac</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ backend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victor Yakubu ]]>
                </dc:creator>
                <pubDate>Fri, 08 Mar 2024 11:04:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/Swimm-Images-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>An API is a technology that powers communication between software applications on the internet. API stands for Application Programming Interface, and it is basically a set of rules and protocols that define how different software can interact with each other. </p>
<p>Imagine having two different programs: program A and program B. For these two programs to communicate together, an API is needed, and a set of rules ensure that they know what to expect when they interact with each other.</p>
<p>As a backend developer, your responsibilities involve building server-side applications, handling data storage, and providing the necessary functionalities to do all these through APIs. </p>
<p>There are <a target="_blank" href="https://blog.postman.com/different-types-of-apis/">different types of APIs</a> like REST, GraphQL, gRPC, SOAP, and WebSockets. However, when it comes to web development, one is more popular, and that is the <a target="_blank" href="https://www.freecodecamp.org/news/what-is-a-rest-api/">REST API</a>.</p>
<p>In this article, you will learn how to create a CRUD API with Node.js and Express using the REST architecture, and by the end of this article, you should have a fully functional API that is able to perform CRUD operations.</p>
<p>So, let's dive into the world of backend development with Node.js and Express and get started on our journey to building a CRUD API.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-a-crud-api">What is a CRUD API?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-nodejs">What is Node.js?</a></li>
<li><a class="post-section-overview" href="#heading-why-node">Why Node?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-nodejs">How to Install Node.js</a></li>
<li><a class="post-section-overview" href="#heading-what-is-express">What is Express?</a></li>
<li><a class="post-section-overview" href="#heading-why-do-you-need-express">Why do You Need Express?</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisite<strong>s</strong></a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-development-environment">How to Set Up Your Development Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-server-for-your-crud-restful-api-with-nodejs-and-express">How to Set up a server for Your CRUD Restful API with Node.js and Express</a></li>
<li><a class="post-section-overview" href="#heading-crud-api-example">CRUD API Example</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-api-routes">How to Create API Routes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-your-own-crud-api">How to Create Your own CRUD API</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-get-users-endpoint">How to Create the GET /users Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-your-api-get-request">How to Test Your API GET Request</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-post-users-endpoint">How to Create the POST /users Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-post-request">How to Test the POST Request</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-get-usersid-endpoint">How to Create the GET /users/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-get-request">How to Test the GET Request</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-delete-usersid">How to Create the DELETE /users/:id</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-delete-request">How to Test the DELETE Request</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-patch-usersid-endpoint">How to Create the PATCH /users/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-test-the-patch-request">How to Test the PATCH Request</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping UP</a></li>
</ul>
<h2 id="heading-what-is-a-crud-api">What is a CRUD API?</h2>
<p>In web development, CRUD operations are the bread and butter of backend systems. This is because they allow you to "Create", "Read", "Update", and "Delete" data through your API. </p>
<p>Here's a quick overview of the four primary HTTP methods associated with CRUD operations:</p>
<ul>
<li><strong>GET</strong>: Used for reading or retrieving data from the server.</li>
<li><strong>POST</strong>: Used for creating new data on the server.</li>
<li><strong>PUT</strong>: Used for updating existing data on the server.</li>
<li><strong>DELETE</strong>: Used for removing data from the server.</li>
</ul>
<p>Virtually every web application interacts with a database to perform these four core operations. Whether it's a social media platform, an e-commerce website, or a weather app, they all rely on creating, reading, updating, and deleting data. </p>
<p>For example, WhatsApp recently added an edit feature to the application, allowing users to make corrections to an already-sent message. That's one part of the CRUD operation in action (updating).</p>
<p>In the context of building a web API, these operations become the backbone of how your application interacts with data. Your API provides endpoints that allow client applications (like web or mobile apps) to perform these operations on the server. </p>
<p>This communication between the client and the server is the essence of web development, and understanding how to create a CRUD API is a crucial skill for a web developer.</p>
<h2 id="heading-what-is-nodejs">What is Node.js?</h2>
<p>Node.js is an open-source and cross-platform runtime environment for executing JavaScript code outside of a browser. Quite often, we use it to build back-end services, also called APIs. Node is ideal for building highly scalable, data-intensive and real-time back-end services that power our client applications</p>
<h2 id="heading-why-node">Why Node?</h2>
<ul>
<li>It is one of the most popular choices for building the backend.</li>
<li>You get to write JavaScript across your entire stack, making it easier to transition from either a frontend developer to a backend developer and vice versa.</li>
<li>It allows for easy scaling of applications, making it a good choice for large-scale professional projects.</li>
<li>It is fast and non-blocking. This is because of the asynchronous event-driven nature of Node.js.</li>
<li>Node.js has a vibrant community and a rich ecosystem of packages and libraries.</li>
</ul>
<h2 id="heading-how-to-install-nodejs">How to Install Node.js</h2>
<p>Installation steps:</p>
<ol>
<li>Download the Mac/Windows installer from the <a target="_blank" href="https://nodejs.org/en/download">Node.js website</a>.</li>
<li>Choose the Long-Term Support (LTS) version that’s shown on the left</li>
<li>After downloading, install/run the installer, and then follow the prompts. (You will have to click the NEXT button a bunch of times and accept the default installation settings</li>
<li>To confirm that Node has been successfully installed, open your terminal and run the command. (For Windows, you might need to restart your command before running it.)</li>
</ol>
<pre><code>node –version
</code></pre><h2 id="heading-what-is-express">What is Express?</h2>
<p>Express is a fast, unopinionated, and minimalist web backend or server-side web framework for Node.js. Basically, it gives you the ability to build your APIs how you want them, with less code.</p>
<p>It is a framework built on top of Node.js that allows you to create your Backend with ease. You can use Express in combination with frontend frameworks like React, Angular, or Vue to build full-stack applications.</p>
<h2 id="heading-why-do-you-need-express">Why do You Need Express?</h2>
<ul>
<li>It makes building web applications with Node.js much easier.</li>
<li>It is extremely light, fast and free.</li>
<li>It is used for both server-rendered apps as well as API/Microservices.</li>
<li>It is the most popular Node.</li>
<li>It gives you full control over requests and responses.</li>
</ul>
<h2 id="heading-prerequisites">Prerequisite<strong>s</strong></h2>
<p>To follow along, you'll need to have the following:</p>
<ul>
<li>Basic knowledge of JavaScript</li>
<li>Download and install <a target="_blank" href="https://nodejs.org/en">Node.js</a> and <a target="_blank" href="https://www.postman.com/downloads/">Postman</a> on your computer</li>
</ul>
<p>See the complete code for this tutorial on <a target="_blank" href="https://github.com/Aviatorscode2/crud-api-tutorial">Github</a>.</p>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development Environment</h2>
<p>Before diving into creating your API, let's go through the process of creating a basic server on your local computer. </p>
<p>Here are the steps to follow:</p>
<h3 id="heading-step-1-create-directory">Step #1 – Create Directory</h3>
<p>Create a directory/folder on your computer. Open the folder in a code editor</p>
<h3 id="heading-step-2-create-indexjs-file">Step #2 – Create index.js File</h3>
<p>Create an <strong>index.js</strong> file inside the folder using this command:</p>
<pre><code>touch index.js
</code></pre><h3 id="heading-step-3-initialize-npm">Step #3 – Initialize NPM</h3>
<p>Initialize NPM inside the folder by running this command in your terminal:</p>
<pre><code>npm init -y
</code></pre><p>The command will create a <strong>package.json</strong> file with default values.</p>
<h3 id="heading-step-5-install-express">Step #5 – Install Express</h3>
<p>Use the command below to install Express.js</p>
<pre><code>npm install express
</code></pre><p>After installing Express, go to the <strong>package.json</strong> file and include <strong>“type”: “module”</strong>. This declaration will tell Node that this project will be using <a target="_blank" href="https://nodejs.org/api/packages.html#type">ES6 module syntax</a> (import/export) instead of common.js, which is the default in Node.  </p>
<p><img src="https://lh7-us.googleusercontent.com/s0sHrHSK7ulqOU4Ddw6WzER6waGEGaCxV26mk-ieuqDVKYBZSKlJ1aDW8WXbCOlfzC1xcW8lXh1-HVSNnYUXYM3MRmmy0N-6uQh-J3qDnjHtxB5atRbJQ-cxR1AWzLTa9RTwv_cXNXpNGz3lbSBHejM" alt="Image" width="600" height="400" loading="lazy">
<em>package.json file with <code>type:module</code></em></p>
<h2 id="heading-how-to-set-up-a-server-for-your-crud-restful-api-with-nodejs-and-express">How to Set up a server for Your CRUD Restful API with Node.js and Express</h2>
<p>To create a CRUD <a target="_blank" href="https://www.freecodecamp.org/news/what-is-rest-rest-api-definition-for-beginners/#:~:text=An%20API%20that%20complies%20with%20some%20or%20all%20of%20the%20six%20guiding%20constraints%20of%20REST%20is%20considered%20to%20be%20RESTful.">restful</a> API, you first need to set up your server. You can do this by following these steps:</p>
<h3 id="heading-step-1-write-your-server-application-code-inside-the-indexjs-file">Step #1 – Write your Server Application Code inside the index.js file</h3>
<p>Basically, a server code will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> ‘body-parser

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

app.use(bodyParser.json());

app.listen(PORT, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port: http://localhost:<span class="hljs-subst">${PORT}</span>`</span>));
</code></pre>
<p>Here's an explanation for the code above:</p>
<ul>
<li>In the first line, we imported <code>express</code> from the Express module that we installed.</li>
<li>The <code>bodyParser</code> comes with Express, and it allows us to take in the incoming POST request body.</li>
<li>Next, we created an <code>app</code> using the <code>express</code> object.</li>
<li>We then specified the port for the application – it was set to <strong>5000</strong> (if you get an error using this port, it might be that the port is currently being used by a different app, so you can either change your port or stop the other app from using the port).</li>
<li>Next, we specified that JSON data will be used in the application.</li>
<li>Once that was created, we used the <code>listen</code> method on the <code>app</code> to make our application listen for incoming requests. The method accepts two things: the <strong>PORT</strong>, which is where we would be listening for requests from our client side, and a callback function that will be triggered when our server is set up.</li>
</ul>
<h3 id="heading-step-2-start-the-server">Step #2 – Start the Server</h3>
<p>Now you can start your server by running this command. If you used a different file, replace index.js with the file name where the server is located.</p>
<pre><code>node index.js
</code></pre><p>Now your server should be running on <strong>port 5000</strong>. You can verify that your server is running on your terminal</p>
<h3 id="heading-step-3-install-nodemon-optional">Step #3 – Install Nodemon (Optional)</h3>
<p>At the moment, anytime you make changes to your server file, you will need to restart the server before your changes can reflect (you can try it and see). So to take care of this challenge, you can use Nodemon. Run the command to install it:</p>
<pre><code>npm install nodemon
</code></pre><p>To use Nodemon, head over to your <strong>package.json</strong> file and set up a script. Replace your start script with this instead:</p>
<pre><code><span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon index.js"</span>
</code></pre><p>Note that <strong>index.js</strong> is the file where the server code is written.</p>
<p>Now you can start your server by running this command:</p>
<pre><code>npm start
</code></pre><p>With this code, we've set up a server that listens on port 5000 and prints a message when it starts. But this is just the beginning because our server needs to do much more. </p>
<p>Let's explore how to handle API requests next.</p>
<h2 id="heading-crud-api-example">CRUD API Example</h2>
<p>Let's start by defining the API routes for each CRUD operation. These routes will serve as the entry points for your API, and they will map to specific actions we want to perform on our data. </p>
<p>In our case, these actions are creating, reading, updating, and deleting data.</p>
<h2 id="heading-how-to-create-api-routes">How to Create API Routes</h2>
<p>When the port (<a target="_blank" href="http://localhost:5000/">http://localhost:5000/</a>) is opened in a browser, you will get an error.</p>
<p><img src="https://lh7-us.googleusercontent.com/p-3qnXzvHDxcsbhpYXO4VMopivQMhqgSPwSTXXDQJW_2GRhFFvkpL8JitNShGcrjyQiMx87ZwkK_4iEbs3JieTdRJQ13Q94O0hV7U9mwOpcm9ET7Yngb2TXQpItUrpepYzeXzg4rZMGdnxonhMREHAo" alt="Image" width="600" height="400" loading="lazy">
<em>localhost:5000 in the browser without any routes</em></p>
<p>This is because Node.js and Express are all about routing, and we don't any routes yet. </p>
<p>You can define API routes using the <code>app.get()</code>, <code>app.post()</code>, <code>app.put()</code>, and <code>app.delete()</code> methods in your Express application (in the <strong>index.js</strong> file). </p>
<p>Here's how to create a route to handle GET requests using the <code>app.get()</code> function:</p>
<pre><code>app.get(<span class="hljs-string">'/'</span>, (req, res)
</code></pre><p>The <code>app.get()</code> function accepts two parameters. The first is used to specify the path (in this case, it is '/'). </p>
<p>The next parameter is a callback function where you define what happens when the GET request is called. The function also has <a target="_blank" href="https://www.freecodecamp.org/news/express-explained-with-examples-installation-routing-middleware-and-more/">two parameters</a>: the request body (<code>req</code>), which can contain information such as the request query string, parameters, body, and HTTP headers. While the response object (<code>res</code>) contains the information you want to send </p>
<p>Here is the complete code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> <span class="hljs-string">'body-parser'</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">5000</span>;

app.use(bodyParser.json());

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'[GET ROUTE]'</span>);
    res.send(<span class="hljs-string">'HELLO FROM HOMEPAGE'</span>);
})

app.listen(PORT, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port: http://localhost:<span class="hljs-subst">${PORT}</span>`</span>));
</code></pre>
<p>When you head back to <a target="_blank" href="http://localhost:5000/">http://localhost:5000/</a> and refresh it, you shouldn’t get an error anymore.</p>
<p><img src="https://lh7-us.googleusercontent.com/6289p5Vl_k4v2ULLd5iUVCpr-sykpbcEytcHsqoJZTB4MgWgDEfVuH1_4aTt0w9ThAhFNCn_rMrlwNFB2hfgOKWQ3znH3MHnHRxh0sd1czb_ntBHMIWS6HtAIo3yuCgDEFK7RVFGvTel0s89T3qTKjc" alt="Image" width="600" height="400" loading="lazy">
<em>localhost:5000 in the browser with GET route</em></p>
<h2 id="heading-how-to-create-your-own-crud-api">How to Create Your own CRUD API</h2>
<p>For this API, you will be handling a set of users. Handling users in a database is a great example because it is a common use case in most applications. </p>
<p>Here are the API endpoints you will be creating:</p>
<ol>
<li>GET /users - find all users</li>
<li>POST /users - creates a user</li>
<li>GET /users/:id - finds a specific user</li>
<li>DELETE /users/:id - deletes a specific user</li>
<li>PATCH /users/:id - updates a specific user.</li>
</ol>
<h3 id="heading-how-to-create-the-get-users-endpoint">How to Create the GET /users Endpoint</h3>
<p>Reading data is one of the most common operations in an API. In this example, you will be getting the list of all the users in your mock database. This information will be presented in JSON format.</p>
<p>To define a route to retrieve users' data from the database, follow these steps:</p>
<ul>
<li>Create a new folder called routes</li>
<li>Create a new file called <strong>users.j</strong>s inside the routes folder.</li>
<li>Write the code to set up the GET router.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-comment">// Mock database</span>
<span class="hljs-keyword">const</span> users = [
  {
    <span class="hljs-attr">first_name</span>: <span class="hljs-string">'John'</span>,
    <span class="hljs-attr">last_name</span>: <span class="hljs-string">'Doe'</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">'johndoe@example.com'</span>,
  },
  {
    <span class="hljs-attr">first_name</span>: <span class="hljs-string">'Alice'</span>,
    <span class="hljs-attr">last_name</span>: <span class="hljs-string">'Smith'</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">'alicesmith@example.com'</span>,
  },
];

<span class="hljs-comment">// Getting the list of users from the mock database</span>
router.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.send(users);
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router
</code></pre>
<p>In this code snippet:</p>
<ul>
<li><code>import express from 'express';</code> imports the Express.js framework</li>
<li><code>const router = express.Router();</code> creates a fresh router instance, stored in the variable router.</li>
<li>The <code>users</code> variable serves as the mock database containing an array of users.</li>
<li>The <code>router.get()</code> function sets up a route that responds to HTTP GET requests.</li>
<li>The second part of the code <code>(req, res) =&gt; { ... }</code> is a callback function. It gets executed when a request is made to the GET route.</li>
<li>Inside the callback function, we used <code>res.send(users)</code> to send a response back to the client. In this example, we're sending the <code>users</code> variable as the response. So when a user hits the GET URL, the server responds by sending the data inside the <code>users</code> variable in JSON format to the client.</li>
</ul>
<p>Save your changes in the <strong>users.js</strong> file. Then do the following in the <strong>index.js</strong> file:</p>
<p>import your user routes from <strong>user.js</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> userRoutes <span class="hljs-keyword">from</span> <span class="hljs-string">'./routes/users.js'</span>
</code></pre>
<p>Use the <code>app.use</code> method, and specify the path and router handler:</p>
<pre><code class="lang-javascript">app.use(<span class="hljs-string">'/users'</span>, userRoutes);
</code></pre>
<p>When a user visits <a target="_blank" href="http://localhost:5000/users">http://localhost:5000/users</a>, the router is triggered. It effectively acts as a filter, determining when a specific set of routes should be applied.</p>
<p>Here is the complete code for the <strong>index.js</strong> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> bodyParser <span class="hljs-keyword">from</span> <span class="hljs-string">'body-parser'</span>
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">import</span> userRoutes <span class="hljs-keyword">from</span> <span class="hljs-string">'./routes/users.js'</span>

<span class="hljs-keyword">const</span> PORT = <span class="hljs-number">5000</span>;

app.use(bodyParser.json());

app.use(<span class="hljs-string">'/users'</span>, userRoutes);

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> res.send(<span class="hljs-string">'HELLO FROM HOMEPAGE'</span>))

app.get(<span class="hljs-string">'/'</span>, (req, res));

app.listen(PORT, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port: http://localhost:<span class="hljs-subst">${PORT}</span>`</span>));
</code></pre>
<h4 id="heading-how-to-test-your-api-get-request"><strong>How to Test Your API GET Request</strong></h4>
<p>You can use either a browser (browsers can only be used to perform GET requests) or Postman to test the GET request. </p>
<p>So copy your API URL, <a target="_blank" href="http://localhost:5000/users">http://localhost:5000/users</a>, and paste it either on Postman or in your browser. If you are using Postman, you will first need to make a GET request, then paste your API URL, and then click on send. After that, you will see the list of users in your Postman console.</p>
<p><img src="https://lh7-us.googleusercontent.com/XBhjewUFTBvBhc2larsYwqzS3-RHp7qFBrO4lvScf91EUFO5TEgt83iU48h9ArDK3EbrPwdS7_-WkI51JkDUHH4v2U9pWXdYMSbKeCpQrYRunvhuvAIAadzcAyj8y0hojjxs1CIlAo7TigoTJrM3y5c" alt="Image" width="600" height="400" loading="lazy">
<em>postman GET route test</em></p>
<h3 id="heading-how-to-create-the-post-users-endpoint">How to Create the POST /users Endpoint</h3>
<p>You can use the POST request to add data to your database. It accepts input from the client and stores it in the database. To create data in our API, we'll define a route that accepts POST requests and saves the data to the mock database you have set up. </p>
<p>But before that, you'll need the UUID package. Use this command to install it:</p>
<pre><code>npm install uuid
</code></pre><p>This package will help generate a unique ID for each user you will be creating. This will be useful when you are implementing the GET, DELETE, and PATCH user by ID requests, where you will need a way to identify a specific user.</p>
<p>So in the <strong>users.js</strong> file, do the following:</p>
<p>Import the <code>uuid</code> package:</p>
<pre><code><span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;
</code></pre><p>Secondly, you'll have to implement the code for the POST request. </p>
<p>Here is what it looks like:</p>
<pre><code class="lang-javascript">router.post(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> user = req.body;

    users.push({ ...user, <span class="hljs-attr">id</span>: uuidv4() });

    res.send(<span class="hljs-string">`<span class="hljs-subst">${user.first_name}</span> has been added to the Database`</span>);
})
</code></pre>
<p>In the code snippet:</p>
<ul>
<li>The <code>router.post()</code> function sets up a route that responds to HTTP POST requests. This means that when a client sends a POST request to the root URL of your application, this route will be triggered.</li>
<li>Within the callback function <code>(req, res) =&gt; { ... }</code>, we access the <code>req</code> object, which represents the incoming request made by the client. Specifically, we're interested in the <code>req.body</code> property. This property contains the data (first name, last name, and email) that the client will send as part of the POST request's body.</li>
<li>With <code>const user = req.body</code> we extract this data from <code>req.body</code> and store it in the <code>user</code> variable.</li>
<li>Next, we added the <code>user</code> data to an array called <code>users</code>. To ensure each user has a unique identifier, we generate a universally unique identifier (UUID) using a function like <code>uuidv4()</code> and include it as id in the user object. This helps in keeping user records distinct and identifiable.</li>
<li>Finally, we used <code>res.send()</code> to send a response back to the client. In this case, we're sending a simple message notifying the client that the user has been successfully added to the database. The message includes the user's first name for a personalized touch.</li>
</ul>
<p>Here is the complete code</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;

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

<span class="hljs-keyword">const</span> users = [];

<span class="hljs-comment">// Adding users to our mock database</span>

router.post(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> user = req.body;

    users.push({ ...user, <span class="hljs-attr">id</span>: uuidv4() });

    res.send(<span class="hljs-string">`<span class="hljs-subst">${user.first_name}</span> has been added to the Database`</span>);
})  

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router
</code></pre>
<h4 id="heading-how-to-test-the-post-request"><strong>How to Test the POST Request</strong></h4>
<p>Here are the steps to follow to make a POST request on Postman:</p>
<ul>
<li>Go to Postman</li>
<li>Open a new request tab</li>
<li>Select "POST" from the list of available HTTP methods</li>
<li>In the URL field, enter the full URL where you want to send the POST request (<a target="_blank" href="http://localhost:5000/users">http://localhost:5000/users</a>)</li>
<li>Click on the "Body" tab in the request window.</li>
<li>Choose the format in which you want to send your POST data (choose JSON).</li>
<li>Enter the data you want to send in the request body. This data should match the format expected by the server.</li>
<li>Finally, click on “Send”  </li>
</ul>
<p><img src="https://lh7-us.googleusercontent.com/olNqMdggCcvhUotN9ospAjg8r7t-HE_3yUqGrEkf_dKnCGTwFiKWQJB3x4dccUbHPlYbP-j8S7a2xBG3TpMvceVdmz_nC8zRtaRQzfeknyyo-OQJDwuSFZJkWPiQctDkoTYfZCsVnE1ljQN96Hxow54" alt="Image" width="600" height="400" loading="lazy">
<em>postman POST route test</em></p>
<p>If it is successful, you will get a response saying, “Daanny has been added to the database."</p>
<p>To confirm if it has been added, make a GET request, and you should see the new user added to your database. (Note: This user information will be lost when your server restarts since it’s not saved to an actual database).</p>
<p><img src="https://lh7-us.googleusercontent.com/cHmJ3hcsMb5Vnj9zh_kSdqBMRrgtR1pQJ3-_DgHgukwdtyLrnG5AN0jyL4gGtzyTYUJj4w_ENO6ZqVsMZLqdnRytOgP4tR5A2B2T_TnDHNbRDEb9JAGF7SmTwVVwBczzg02JmLfWAucyeyMlnPs1Ehg" alt="Image" width="600" height="400" loading="lazy">
<em>postman GET route test</em></p>
<h3 id="heading-how-to-create-the-get-usersid-endpoint">How to Create the GET /users/:id Endpoint</h3>
<p>Fetching specific data based on a unique identifier, such as a user ID, is a common operation. It's often essential for building features like user profiles or retrieving individual records from a database. </p>
<p>In this section, you’ll explore how to use this endpoint (users/:id) to retrieve user information based on a provided user ID. </p>
<p>Let's get started!</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">'/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { id } = req.params;

    <span class="hljs-keyword">const</span> foundUser = users.find(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id === id)

    res.send(foundUser)
});
</code></pre>
<p>Here's what this code snippet does:</p>
<ul>
<li>The <code>router.get()</code> function sets up a route that responds to HTTP GET requests. In this example, we've defined a route with ('/:id'). The :id part is a route parameter, which allows us to capture a dynamic value from the URL. In this case, it represents the user ID we want to retrieve.</li>
<li>Within the callback function <code>(req, res) =&gt; { ... }</code>, we can access the <code>req</code> object, which represents the incoming request made by the client. Specifically, we're interested in <code>req.params</code>, which holds the values of route parameters. In this case, we destructure <code>id</code> from <code>req.params</code>, effectively extracting the user ID from the URL. For example, if a client makes a GET request to /users/123, the id will be '123'.</li>
<li>We used the <code>.find()</code> method to search through this data based on the user ID (id) captured from the URL. This method attempts to find a user whose ID matches the provided id.</li>
<li>Once we located the user data (if it exists), we send it as the response using <code>res.send(foundUser)</code>. The <code>foundUser</code> variable contains the user object that matches the requested ID.</li>
</ul>
<h4 id="heading-how-to-test-the-get-request"><strong>How to Test the GET Request</strong></h4>
<p>In testing the API, follow these steps:</p>
<ul>
<li>Go to your POST request tab and make as many requests as you want to add a new user to the database.</li>
<li>Go to your GET request tab and make a request to see the list of users you have added</li>
</ul>
<p><img src="https://lh7-us.googleusercontent.com/qEuvm-1QKHvGmFCmru5dF2b9JSW5ua_dMcovZaKFZL_NChfSQqaazX4QvvSrSkjMzTO9Yqon5zhsZ5ZZwrWO0WifthlOKfboojC6ws8Fju2HK5TcE1oLvZZhOaO5xljRIUvYt_oun_NsIH13sq2Yf0o" alt="Image" width="600" height="400" loading="lazy">
<em>postman GET route test</em></p>
<ul>
<li>Copy the id of any of the users on the list</li>
<li>Create a new GET request tab, copy in the base API URL, and add the id of any of the users to it. It should be in a format like this: <a target="_blank" href="http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593">http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593</a></li>
<li>Click on “Send”. If it’s successful, you will see the user information of the user id you used for the request</li>
</ul>
<p><img src="https://lh7-us.googleusercontent.com/ui9cj6HDXIifMjzlnICvnzgIGOssvRbGeCrlos2DXG541b4r9Dsn0mVrXZBfyCwvO6gh3yovrbsDD1I7EU0-5j7r3fRIrQ4XFX1QR-vlFJlXuXb1Ht753re7ZDf2cC7VyPyLgee6a6gZmwjnkCb8RI0" alt="Image" width="600" height="400" loading="lazy">
<em>postman GET route test</em></p>
<h3 id="heading-how-to-create-the-delete-usersid">How to Create the DELETE /users/:id</h3>
<p>Sometimes, it's necessary to remove user accounts or specific records from a database for various reasons, such as account deactivation. </p>
<p>Here, you will explore how to use this endpoint to delete user data based on a provided user ID.</p>
<p>To delete data, we'll define a route that accepts DELETE requests and removes the data from the database.</p>
<p>See the code to delete a user from a database below</p>
<pre><code class="lang-javascript">router.delete(<span class="hljs-string">'/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { id } = req.params;

  users = users.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id !== id)

  res.send(<span class="hljs-string">`<span class="hljs-subst">${id}</span> deleted successfully from database`</span>);
});
</code></pre>
<p>Here's what this code does:</p>
<ul>
<li>The <code>router.delete()</code> function sets up a route that responds to HTTP DELETE requests. In this example, we've defined a route with ('/:id'), where :id is a route parameter. It captures a dynamic value from the URL, representing the user ID we want to delete.</li>
<li>In the callback function <code>(req, res) =&gt; { ... }</code>, we can access the <code>req</code> object, which represents the incoming request made by the client. Specifically, we're interested in <code>req.params</code>, which holds the values of route parameters. Here, we destructure id from <code>req.params</code>, extracting the user ID from the URL. For instance, if a client sends a DELETE request to /users/123, id will be '123'.</li>
<li>Assuming that we have an array or database (users) containing user data, we employ the <code>.filter()</code> method to create a new array that excludes the user with the matching ID (id). This effectively removes the user from the data store.</li>
<li>After successfully deleting the user, we send a response back to the client using <code>res.send()</code>. The response contains a message confirming the deletion, including the user's ID that was deleted from the database.</li>
</ul>
<h4 id="heading-how-to-test-the-delete-request"><strong>How to Test the DELETE Request</strong></h4>
<p>Here are the steps to delete a user from the database on Postman:</p>
<ul>
<li>Go to Postman</li>
<li>Open a new request tab</li>
<li>Select "DELETE" from the list of available HTTP methods</li>
<li>Enter the URL. It should contain the id of the user you want to delete (for example: <a target="_blank" href="http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593">http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593</a>). If you don’t have a user in your database, you will need to create one and copy the id.</li>
<li>Click on “Send”.  </li>
</ul>
<p><img src="https://lh7-us.googleusercontent.com/bTO6dcTaujyxm7ruPcyCJTzMfZemFop1oqU803Fif2kCeq1Z2q3uB1-JHB1aK4-ePIimPvb1LBYuty8_YFd7xP_i8UVhFZewWHlmwKy3MlWssMWtdaBnXtCkyB8NZebDnldJzRXc_v0Fs7MS4rZJq_g" alt="Image" width="600" height="400" loading="lazy">
<em>postman DELETE route test</em></p>
<p><img src="https://lh7-us.googleusercontent.com/B9YHqAtEyg1f0O0CAojNJDXjK212LCxFodc9Ld3j04bdZsK9R5qHExSxaKGCAqgI0W79jHJ2bN3l9GkVgB3DYAd192zB9LzThvcAZJFuXoBO5JUqcUKWyBWcc6q4KirQA4B6Hi6t1NN3eU8e-dH10pY" alt="Image" width="600" height="400" loading="lazy">
<em>postman DELETE route test</em></p>
<h3 id="heading-how-to-create-the-patch-usersid-endpoint">How to Create the PATCH /users/:id Endpoint</h3>
<p>There are times when you don't need to update an entire resource or object. Instead, you'd want to make partial modifications or adjustments. This is where the HTTP PATCH request comes into play.</p>
<p>For example, after creating a new user, you can change either the first name, last name, or email of that user using the PATCH request. Let’s see how to do that.</p>
<pre><code class="lang-javascript">router.patch(<span class="hljs-string">'/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { id } = req.params;

  <span class="hljs-keyword">const</span> { first_name, last_name, email} = req.body;

  <span class="hljs-keyword">const</span> user = users.find(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id === id)

  <span class="hljs-keyword">if</span>(first_name) user.first_name = first_name;
  <span class="hljs-keyword">if</span>(last_name) user.last_name = last_name;
  <span class="hljs-keyword">if</span>(email) user.email = email;

  res.send(<span class="hljs-string">`User with the <span class="hljs-subst">${id}</span> has been updated`</span>)

});
</code></pre>
<p>Here's what this code snippet accomplishes:</p>
<ul>
<li>The <code>router.patch()</code> function sets up a route that responds to HTTP PATCH requests. In this example, we've defined a route with ('/:id'), where :id is a route parameter. It captures the dynamic value from the URL, representing the user ID we want to update.</li>
<li>Within the callback function <code>(req, res) =&gt; { ... }</code>, we can access the <code>req</code> object, which represents the incoming request made by the client. Specifically, we're interested in <code>req.params</code>, which hold the values of route parameters (id in this case), and <code>req.body</code>, which contains the data to be updated.</li>
<li>Next, we used <code>.find()</code> to locate the user object with the matching ID (id). Once found, we can proceed to modify the user's data based on the content of <code>req.body</code>. We also checked if first_name, last_name, or email properties exist in <code>req.body</code>. If they do, we can update the corresponding properties of the user object with the new values. This allows us to make selective changes to the user's data without affecting other attributes.</li>
<li>After successfully applying the requested modifications, we send a response back to the client using <code>res.send()</code>. The response includes a message confirming the successful update of the user data, along with the user's ID.</li>
</ul>
<h4 id="heading-how-to-test-the-patch-request"><strong>How to Test the PATCH Request</strong></h4>
<p>Follow these steps to make a PATCH request in Postman:</p>
<ul>
<li>Go to Postman</li>
<li>Open a new request tab</li>
<li>Select "PATCH" from the list of available HTTP methods</li>
<li>Enter URL; the URL will contain the id of the user you want to delete (for example: <a target="_blank" href="http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593">http://localhost:5000/users/734a9e75-b3f5-415f-82fb-79b4fdf1a593</a>). If you don’t have a user in your database, you will need to create one and copy the id.</li>
<li>Click on the "Body" tab in the request window and choose the format in which you want to send your PATCH data (for example: JSON, form-data, x-www-form-urlencoded).</li>
<li>Enter the data you want to send in the request body. This data should only include the specific changes you want to make to the resource.</li>
<li>Then click the "Send" button. Postman will send the PATCH request to the specified URL with the provided data.</li>
</ul>
<p><img src="https://lh7-us.googleusercontent.com/K1OH_u-2DOJbkMqlQ3uJow9XNKh0iOmE8fedCCspUiQIHcvm-DmIorFvZcApoDWGSK4YMkFR7RtcHBmzMZaJUyXy7SMDJWxH_PDLFmugGPNQDmKzM6HE3tPOBQZaS1388bZzLlmcTThQa_wy1ZPrm1g" alt="Image" width="600" height="400" loading="lazy">
<em>postman PATCH route test</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>APIs are the linchpin connecting various software components and enabling them to work together seamlessly. They allow them to communicate, share data, and perform tasks. In the context of web development, APIs enable the web to function as we know it today.</p>
<p>In this tutorial, we explored backend development by creating a CRUD API with Node.js and Express. We covered various concepts, like how to set up a development environment, create a server with Express and Node.js, and most importantly, how to handle CRUD operations and test your API using Postman.</p>
<p>While we've covered fundamental aspects of API creation in this tutorial, there is still a vast landscape of knowledge to explore as regards to APIs. These include how to secure your API by adding authentication, how to use middleware, database interaction, API deployment, and a lot more.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Backend Development by Building a CRUD API with Node and MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ A key part of most backend development projects is CRUD. Simply put, CRUD stands for Create, Read, Update, Delete. These fundamental operations form the basis of how data is handled in many applications, making understanding them crucial for backend ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/crud-api-with-node-js-express-mongodb/</link>
                <guid isPermaLink="false">66b201eda8b92c932923643f</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 14 Feb 2024 15:05:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/crudtutroail.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A key part of most backend development projects is CRUD. Simply put, <strong>CRUD</strong> stands for <strong>Create, Read, Update, Delete</strong>. These fundamental operations form the basis of how data is handled in many applications, making understanding them crucial for backend development.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will throw you into the world of <strong>backend development</strong> by guiding you through building a <strong>CRUD API</strong> from scratch. You will use Node.js, Express, and MongoDB. The course is led by popular instructor and experienced developer Haris Iftikhar.</p>
<p>Now, what about the technologies? This course will equip you with three powerful tools:</p>
<ul>
<li><strong>Node.js:</strong> A JavaScript runtime environment that allows you to run JavaScript code outside of the browser, perfect for building server-side applications.</li>
<li><strong>Express.js:</strong> A popular web framework built on top of Node.js, providing structure and tools to simplify web development.</li>
<li><strong>MongoDB:</strong> A NoSQL database, meaning it stores data in a flexible and document-oriented manner, ideal for modern applications.</li>
</ul>
<p>Together, these technologies form the backbone of the <strong>MERN Stack</strong>, a widely used combination for building full-stack web applications. In this course, you'll be focusing on the MEN part (minus the React front-end), laying a solid foundation for your backend development journey.</p>
<p>The course is structured into bite-sized sections, taking you through each step of building your CRUD API:</p>
<ul>
<li><strong>Setting the Stage:</strong> Understand the project outline and get familiar with the tools you'll be using.</li>
<li><strong>Project Essentials:</strong> Dive into <code>package.json</code>, the Express framework, and learn how to run your server efficiently.</li>
<li><strong>Data Management:</strong> Explore API testing tools, utilize Git Bash for version control, and set up your MongoDB database.</li>
<li><strong>Building the API:</strong> Craft your data model, create API endpoints for creating, reading, updating, and deleting data.</li>
<li><strong>Form Handling:</strong> Understand Form URL Encoded data and how to handle it in your API.</li>
<li><strong>Structuring your Code:</strong> Organize your code with routes and controllers, keeping things clean and maintainable.</li>
<li><strong>Testing and Deployment:</strong> Learn how to thoroughly test your API and push your code to GitHub for version control and collaboration.</li>
</ul>
<p>By the end of this course, you'll have built a functional CRUD API using Node, Express, and MongoDB, gaining valuable hands-on experience in backend development. This knowledge will pave the way for you to explore more complex concepts and build even more sophisticated applications in the future.</p>
<p>Watch the full course on the freeCodeCamp.org YouTube channel (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/_7UQPve99r4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a CRUD REST API with NestJS, Docker, Swagger, and Prisma ]]>
                </title>
                <description>
                    <![CDATA[ Welcome to this in-depth guide on crafting a RESTful API with NestJS, Docker, Swagger, and Prisma. My goal here is to teach you how to build robust and efficient backends, regardless of whether you're a seasoned developer or a beginner just dipping y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-crud-rest-api-with-nestjs-docker-swagger-prisma/</link>
                <guid isPermaLink="false">66bb56f70da5b03e481107bf</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Tue, 23 Jan 2024 00:17:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Nestjs_Free_code.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Welcome to this in-depth guide on crafting a RESTful API with NestJS, Docker, Swagger, and Prisma. My goal here is to teach you how to build robust and efficient backends, regardless of whether you're a seasoned developer or a beginner just dipping your toes into the world of coding.</p>
<p>In this journey, we'll be creating a delightful recipe management system. We'll explore the power of NestJS, Docker, Swagger, and Prisma, and harness these cutting-edge technologies to implement CRUD (Create, Read, Update, Delete) operations for managing recipes.</p>
<p>But this tutorial isn't just for the culinary enthusiasts or recipe collectors out there. It's for anyone who's passionate about learning and growing their development skills. </p>
<p>So, buckle up and get ready for an exciting coding adventure as we dive in and start building your very own recipe management system together.</p>
<p>This is what we'll build:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/all-for-swagger-end-product.png" alt="REST API ALL  " width="600" height="400" loading="lazy">
<em>A snapshot of the Swagger UI showcasing all the implemented endpoints.</em></p>
<p>And here's what we'll cover:</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-technologies">Technologies</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-development-environment">Development Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-nestjs-project">How to Set Up the NestJS Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-postgresql-instance-with-docker">How to Create a PostgreSQL Instance with Docker</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-prisma">How to Set Up Prisma</a></li>
<li><a class="post-section-overview" href="#heading-how-to-initialize-prisma">How to Initialize Prisma</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-your-environment-variable">How to Set Your Environment Variable</a></li>
<li><a class="post-section-overview" href="#heading-understanding-the-prisma-schema">Understanding the Prisma Schema</a></li>
<li><a class="post-section-overview" href="#heading-how-to-model-the-data">How to Model the Data</a></li>
<li><a class="post-section-overview" href="#heading-how-to-migrate-the-database">How to Migrate the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-seed-the-database">How to Seed the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-prisma-service">How to Create a Prisma Service</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-swagger">How to Set Up Swagger</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-crud-operations-for-the-recipe-model">How to Implement CRUD Operations for the Recipe Model</a></li>
<li><a class="post-section-overview" href="#heading-how-to-generate-rest-resources-with-nestjs-cli">How to Generate REST Resources with NestJS CLI</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-prismaclient-to-the-recipe-module">How to Add PrismaClient to the Recipe Module</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-get-recipes-endpoint">How to Define the GET /recipes Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-get-recipesid-endpoint">How to Define the GET /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-post-recipes-endpoint">How to Define the POST /recipes Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-patch-recipesid-endpoint">How to Define the PATCH /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-delete-recipesid-endpoint">How to Define the DELETE /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-summary-and-final-remarks">Summary and Final Remarks</a></li>
</ul>
<h2 id="heading-technologies">Technologies</h2>
<p>To build this application, we'll be leveraging the power of the following tools:</p>
<ul>
<li><strong><a target="_blank" href="https://nestjs.com/">NestJS</a></strong>: A progressive Node.js framework for building efficient, reliable, and scalable server-side applications.</li>
<li><strong><a target="_blank" href="https://www.prisma.io/">Prisma</a></strong>: An open-source database toolkit that makes it easy to reason about your data and how you interact with it.</li>
<li><strong><a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a></strong>: A powerful, open source object-relational database system.</li>
<li><strong><a target="_blank" href="https://www.docker.com/">Docker</a></strong>: An open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.</li>
<li><strong><a target="_blank" href="https://swagger.io/">Swagger</a></strong>: A tool for designing, building, and documenting RESTful APIs.</li>
<li><strong><a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a></strong>: A statically typed superset of JavaScript that adds optional types, classes, and modules to the language.</li>
</ul>
<p>Each of these technologies plays a crucial role in creating a robust, scalable, and maintainable application. We'll dive deeper into each one as we proceed.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<h3 id="heading-assumed-knowledge">Assumed Knowledge</h3>
<p>This tutorial is designed to be beginner-friendly, but I do make a few assumptions about what you already know:</p>
<ul>
<li>Fundamentals of TypeScript</li>
<li>Basics of NestJS</li>
<li>Docker</li>
</ul>
<p>If you're not familiar with these, don't fret! I've got you covered. This tutorial will guide you through everything you need to know. </p>
<p>But here are some more resources if you'd like to learn more:</p>
<ul>
<li>For a deeper dive into NestJS, feel free to explore the <a target="_blank" href="https://docs.nestjs.com/">official NestJS documentation</a>.</li>
<li>To learn more about Docker, here's a <a target="_blank" href="https://www.freecodecamp.org/news/the-docker-handbook/">full handbook for beginners</a>.</li>
<li>And for more info on TypeScript, here's a <a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-with-this-crash-course/">helpful crash course</a>.</li>
</ul>
<h2 id="heading-development-environment">Development Environment</h2>
<h3 id="heading-tools-and-technologies">Tools and Technologies</h3>
<p>In this tutorial, we'll use the following tools:</p>
<ul>
<li><a target="_blank" href="https://nodejs.org/en/download/">Node.js</a> – Our runtime environment</li>
<li><a target="_blank" href="https://www.docker.com/get-started/">Docker</a> – For containerizing our database</li>
<li><a target="_blank" href="https://code.visualstudio.com/Download">Visual Studio Code</a> – Our code editor</li>
<li><a target="_blank" href="https://www.postgresql.org/download/">PostgreSQL</a> – Our database</li>
<li><a target="_blank" href="https://docs.nestjs.com/">NestJS</a> – Our Node.js framework</li>
</ul>
<p><strong>Note:</strong> Don't forget to install the Prisma extension for Visual Studio Code. It enhances your coding experience by highlighting Prisma-specific syntax and keywords.</p>
<h2 id="heading-how-to-set-up-the-nestjs-project">How to Set Up the NestJS Project</h2>
<p>NestJS is a progressive Node.js framework that comes with a plethora of advantages, including a powerful Command Line Interface (CLI). This CLI simplifies the process of creating a new NestJS application, making it easy to start a new project anytime, anywhere.</p>
<p>One of the key benefits of NestJS is its rich set of built-in functionalities that significantly streamline the development process, making your life as a developer much easier.</p>
<p>Let's begin by installing the NestJS CLI on your system:</p>
<pre><code class="lang-bash">npm i -g @nestjs/cli
</code></pre>
<p>With the NestJS CLI installed, you're all set to whip up our recipe project. The CLI streamlines the creation of a new NestJS application, making it simple to get started. </p>
<p>To spin up a new project, execute the following command:</p>
<pre><code class="lang-bash">nest new recipe
</code></pre>
<p>After running this command, you'll encounter a prompt like the one you see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Settting-nest.png" alt="Nest CLI Package Manager Prompt" width="600" height="400" loading="lazy">
<em>The Nest CLI prompting for a package manager selection during project setup.</em></p>
<p>As illustrated in the image, the Nest CLI will prompt you to select a package manager. For this project, we'll opt for <code>npm</code>. Once you've made your selection, the CLI will proceed with the project setup, and you'll see a series of operations being performed in your terminal.</p>
<p>Now you can open you project in VSCode (or the editor of your choice). You should see the following files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/After-setting-up-nejst.png" alt="Nest CLI Package Manager Prompt" width="600" height="400" loading="lazy">
<em>The folder structure of the project after it has been created using Nest CLI.</em></p>
<p>Let break down the project structure:</p>
<table>
<thead>
<tr>
<th>Directory/File</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>recipe/</code></td>
<td>Root directory of the project.</td>
</tr>
<tr>
<td><code>├── node_modules/</code></td>
<td>Contains all the npm packages required for the project.</td>
</tr>
<tr>
<td><code>├── src/</code></td>
<td>Contains the source code of the application.</td>
</tr>
<tr>
<td><code>│ ├── app.controller.spec.ts</code></td>
<td>Contains the tests for <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ ├── app.controller.ts</code></td>
<td>Contains a basic controller with a single route.</td>
</tr>
<tr>
<td><code>│ ├── app.module.ts</code></td>
<td>The root module of the application.</td>
</tr>
<tr>
<td><code>│ ├── app.service.ts</code></td>
<td>Contains the services used by <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ └── main.ts</code></td>
<td>The entry point of the application.</td>
</tr>
<tr>
<td><code>├── test/</code></td>
<td>Contains the end-to-end tests for the application.</td>
</tr>
<tr>
<td><code>│ ├── app.e2e-spec.ts</code></td>
<td>Contains the end-to-end tests for <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ └── jest-e2e.json</code></td>
<td>Contains the configuration for the end-to-end tests.</td>
</tr>
<tr>
<td><code>├── README.md</code></td>
<td>The readme file for the project.</td>
</tr>
<tr>
<td><code>├── nest-cli.json</code></td>
<td>Contains the configuration for the NestJS CLI.</td>
</tr>
<tr>
<td><code>├── package-lock.json</code></td>
<td>Contains the exact versions of the npm packages used in the project.</td>
</tr>
<tr>
<td><code>├── package.json</code></td>
<td>Lists the npm packages required for the project.</td>
</tr>
<tr>
<td><code>└── tsconfig.build.json</code></td>
<td>Contains the TypeScript compiler options for the build.</td>
</tr>
</tbody>
</table>

<p>The <code>src</code> directory is the nerve center of our application, hosting the bulk of our codebase. The NestJS CLI has already set the stage for us with several key files:</p>
<ul>
<li><code>src/app.module.ts</code>: This is the root module of our application, serving as the main junction for all other modules.</li>
<li><code>src/app.controller.ts</code>: This file houses a basic controller with a single route: <code>/.</code> When accessed, this route will return a simple 'Hello World!' message.</li>
<li><code>src/main.ts</code>: This is the gateway to our application. It's tasked with bootstrapping and launching the NestJS application.</li>
</ul>
<p>To start your project and see the 'Hello World!' message in action, execute the following command:</p>
<pre><code class="lang-bash">npm run start:dev
</code></pre>
<p>This command triggers a live-reload development server. It vigilantly monitors your files, and if it spots any modifications, it automatically recompile your code and refreshes the server. This ensures that you can see your changes in real-time, eliminating the need for manual restarts.</p>
<p>To verify that your server is operational, head over to <code>http://localhost:3000/</code> in your web browser or Postman. You should be welcomed by a minimalist page showcasing the message <code>Hello World</code>. This is your application's default landing page, a pristine canvas awaiting your creative touch.</p>
<h2 id="heading-how-to-create-a-postgresql-instance-with-docker">How to Create a PostgreSQL Instance with Docker</h2>
<p>To store our recipes REST API, we'll use a PostgreSQL database. Docker will help us containerize this database, ensuring a smooth setup and execution, regardless of the environment.</p>
<p>First, ensure Docker is installed on your system. If not, follow the instructions <a target="_blank" href="https://www.docker.com/get-started">here</a>.</p>
<p>Next, you'll need to create a <code>docker-compose.yml</code> file.</p>
<p>Open the terminal and run the following command:</p>
<pre><code class="lang-bash">touch docker-compose.yml
</code></pre>
<p>This command creates a new <code>docker-compose.yml</code> file in your project's root directory.</p>
<p>Open the <code>docker-compose.yml</code> file and add the following code:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># docker-compose.yml</span>

version: <span class="hljs-string">'3.8'</span>
services:
  postgres:
    image: postgres:13.5
    restart: always
    environment:
      - POSTGRES_USER=recipe
      - POSTGRES_PASSWORD=RecipePassword
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - <span class="hljs-string">'5432:5432'</span>
volumes:
  postgres:
</code></pre>
<p>Here's a quick breakdown of this configuration:</p>
<ul>
<li><code>image: postgres:13.5</code>: Specifies the Docker image for the PostgreSQL database.</li>
<li><code>restart: always</code>: Ensures the container restarts if it stops.</li>
<li><code>environment</code>: Sets the username and password for the database.</li>
<li><code>volumes</code>: Mounts a volume to persist database data, even if the container is stopped or removed.</li>
<li><code>ports</code>: Exposes port <code>5432</code> on both the host machine and the container for database access.</li>
</ul>
<p>Note: If you wish to use a different port, simply change the host machine port. For example, to use port <code>5433</code>, modify the <code>ports</code> section as follows:</p>
<pre><code class="lang-bash">ports:
  - <span class="hljs-string">'5444:5432'</span>
</code></pre>
<p>Note: Before proceeding, ensure port <code>5432</code> is free on your machine. To fire up the PostgreSQL container, execute the following command in your project's root directory (and also make sure you have open the docker desktop app and it is running):</p>
<pre><code class="lang-bash">docker-compose up
</code></pre>
<p>This command spins up the PostgreSQL container and makes it accessible on port <code>5432</code> of your machine. If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-bash">...
 | PostgreSQL init process complete; ready <span class="hljs-keyword">for</span> start up.
postgres-1  |
postgres-1  | 2024-01-12 14:59:33.519 UTC [1] LOG:  starting PostgreSQL 13.5 (Debian 13.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
postgres-1  | 2024-01-12 14:59:33.520 UTC [1] LOG:  listening on IPv4 address <span class="hljs-string">"0.0.0.0"</span>, port 5432
postgres-1  | 2024-01-12 14:59:33.520 UTC [1] LOG:  listening on IPv6 address <span class="hljs-string">"::"</span>, port 5432
postgres-1  | 2024-01-12 14:59:33.526 UTC [1] LOG:  listening on Unix socket <span class="hljs-string">"/var/run/postgresql/.s.PGSQL.5432"</span>
postgres-1  | 2024-01-12 14:59:33.533 UTC [62] LOG:  database system was shut down at 2024-01-12 14:59:33 UTC
postgres-1  | 2024-01-12 14:59:33.550 UTC [1] LOG:  database system is ready to accept connections
</code></pre>
<p>Remember, if you've changed the port number, the output will reflect your chosen port.</p>
<p>If the port is already in use, you'll encounter an error message like this:</p>
<pre><code class="lang-bash">Error starting userland proxy: listen tcp 0.0.0.0:5432: <span class="hljs-built_in">bind</span>: address already <span class="hljs-keyword">in</span> use
</code></pre>
<p>In such a case, free up the port or choose a different one in your <code>docker-compose.yml</code> file.</p>
<p>Note: if you close the terminal window, it will also stop the container. To prevent this, you can run the container in detached mode. This mode allows the container to run indefinitely in the background. </p>
<p>To do this, add a <code>-d</code> option at the end of the command, like so:</p>
<pre><code class="lang-bash">docker-compose up -d
</code></pre>
<p>To stop the container, use the following command:</p>
<pre><code class="lang-bash">docker-compose down
</code></pre>
<p>Congratulations 🎉. You now have your own PostgreSQL database to play around with.</p>
<h2 id="heading-how-to-set-up-prisma">How to Set Up Prisma</h2>
<p>Now that we have our PostgreSQL database up and running, we're ready to set up Prisma. Prisma is an open-source database toolkit that makes it easy to reason about your data and how you interact with it.</p>
<p>Prisma is a powerful tool that offers a wide range of features, including:</p>
<ul>
<li><strong>Database Migrations</strong>: Prisma makes it easy to evolve your database schema over time, without losing any data.</li>
<li><strong>Database Seeding</strong>: Prisma allows you to seed your database with test data.</li>
<li><strong>Database Access</strong>: Prisma provides a powerful API for accessing your database.</li>
<li><strong>Database Schema Management</strong>: Prisma allows you to define your database schema using the Prisma Schema Language.</li>
<li><strong>Database Querying</strong>: Prisma provides a powerful API for querying your database.</li>
<li><strong>Database Relationships</strong>: Prisma allows you to define relationships between your database tables.</li>
</ul>
<p>You can learn more about Prisma <a target="_blank" href="https://www.prisma.io/">here</a>.</p>
<h3 id="heading-how-to-initialize-prisma">How to Initialize Prisma</h3>
<p>To get started with Prisma, we'll need to install the Prisma CLI. This CLI allows us to interact with our database, making it easy to perform database migrations, seeding, and more.</p>
<p>To install the Prisma CLI, execute the following command:</p>
<pre><code class="lang-bash">
npm install prisma -D
</code></pre>
<p>This command installs the Prisma CLI as a development dependency in your project. The <code>-D</code> flag tells npm to install the package as a development dependency.</p>
<p>Next, initialize Prisma in your project by executing the following command:</p>
<pre><code class="lang-bash">
npx prisma init
</code></pre>
<p>This will create a new <code>prisma</code> directory with a <code>schema.prisma</code> file. This is the main configuration file that contains your database schema. This command also creates a <code>.env</code> file inside your project.</p>
<h3 id="heading-how-to-set-your-environment-variable">How to Set Your Environment Variable</h3>
<p>The <code>.env</code> file contains the environment variables required to connect to your database. Open this file and replace the contents with the following:</p>
<pre><code class="lang-bash">
DATABASE_URL=<span class="hljs-string">"postgres://recipe:RecipePassword@localhost:5444/recipe"</span>
</code></pre>
<p>Note: If you changed the port number in your <code>docker-compose.yml</code> file, ensure you update the port number in the <code>DATABASE_URL</code> environment variable with the port number you used.</p>
<p>This environment variable contains the connection string for your database. It's used by Prisma to connect to your database in the docker container.</p>
<h3 id="heading-understanding-the-prisma-schema">Understanding the Prisma Schema</h3>
<p>The <code>schema.prisma</code> file contains the schema for your database. It's written in the Prisma Schema Language, a declarative language for defining your database schema. The <code>prisma/schema.prisma</code> file is the main configuration file for your Prisma setup. It defines your database connection and the Prisma Client generator.</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// prisma/schema.prisma</span>

generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}
</code></pre>
<p>This file is written in the Prisma Schema Language, which is a language that Prisma uses to define your database schema. The <code>schema.prisma</code> file has three main components:</p>
<ul>
<li><strong>Generator</strong>: This section defines the Prisma Client generator. The Prisma Client generator is responsible for generating the Prisma Client, a powerful API for accessing your database.</li>
<li><strong>Datasource</strong>: This section defines the database connection. It specifies the database provider and the connection string. It use <code>DATABASE_URL</code> environment variable to connect to your database.</li>
<li><strong>Model</strong>: This section defines the database schema. It specifies the database tables and their fields.</li>
</ul>
<h2 id="heading-how-to-model-the-data">How to Model the Data</h2>
<p>Now that we have set up our Prisma, we're ready to model our data. We'll be building a recipe management system, so we'll need to define a <code>Recipe</code> model. This model will have various fields.</p>
<p>Open the <code>schema.prisma</code> file and add the following code:</p>
<pre><code class="lang-ts">
 <span class="hljs-comment">// prisma/schema.prisma</span>
 <span class="hljs-comment">// ...</span>
model Recipe {
  id           Int      <span class="hljs-meta">@id</span> <span class="hljs-meta">@default</span>(autoincrement())
  title        <span class="hljs-built_in">String</span>   <span class="hljs-meta">@unique</span>
  description  <span class="hljs-built_in">String</span>?
  ingredients  <span class="hljs-built_in">String</span>
  instructions <span class="hljs-built_in">String</span>
  createdAt    DateTime <span class="hljs-meta">@default</span>(now())
  updatedAt    DateTime <span class="hljs-meta">@updatedAt</span>
}
</code></pre>
<p>Here's a quick breakdown of this model:</p>
<ul>
<li><code>id</code>: This is the primary key of the <code>Recipe</code> model. It's an auto-incrementing integer that uniquely identifies each recipe. It has the <code>@id</code> attribute, which tells Prisma that this field is the primary key. It also has the <code>@default(autoincrement())</code> attribute, which tells Prisma to auto-increment this field.</li>
<li><code>title</code>: This is the title of the recipe. It's a unique string that's used to identify the recipe.</li>
<li><code>description</code>: This is the description of the recipe. It's an optional string that describes the recipe.</li>
<li><code>ingredients</code>: This is the list of ingredients used in the recipe. It's a string that contains a comma-separated list of ingredients.</li>
<li><code>instructions</code>: This is the list of instructions for preparing the recipe. It's a string that contains a comma-separated list of instructions.</li>
<li><code>createdAt</code>: This is the date and time the recipe was created. It's set to the current date and time by default. It has the <code>@default(now())</code> attribute, which tells Prisma to set this field to the current date and time by default.</li>
<li><code>updatedAt</code>: This is the date and time the recipe was last updated. It's set to the current date and time by default.</li>
</ul>
<h2 id="heading-how-to-migrate-the-database">How to Migrate the Database</h2>
<p>Now that we've defined our database schema, we're ready to migrate our database. This will create the database tables and fields defined in our <code>schema.prisma</code> file.</p>
<p>To migrate your database, execute the following command:</p>
<pre><code class="lang-bash">npx prisma migrate dev --name init
</code></pre>
<p>This command will do three things:</p>
<p><strong>Save the migration</strong>: Prisma Migrate will take a snapshot of your schema and figure out the SQL commands necessary to carry out the migration. Prisma will save the migration file containing the SQL commands to the newly created <code>prisma/migrations</code> folder.</p>
<p><strong>Execute the migration</strong>: Prisma Migrate will execute the SQL commands in the migration file, creating the database tables and fields defined in your <code>schema.prisma</code> file.</p>
<p><strong>Generate Prisma Client</strong>: Prisma will generate Prisma Client based on your latest schema. Since you did not have the Client library installed, the CLI will install it for you as well. You should see the <code>@prisma/client</code> package inside dependencies in your package.json file. </p>
<p>Prisma Client is a TypeScript query builder auto-generated from your Prisma schema. It is tailored to your Prisma schema and will be used to send queries to the database.</p>
<p>If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-bash">The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20220528101323_init/
    └─ migration.sql

Your database is now <span class="hljs-keyword">in</span> sync with your schema.
...
✔ Generated Prisma Client (3.14.0 | library) to ./node_modules/@prisma/client <span class="hljs-keyword">in</span> 31ms
</code></pre>
<p>Check the generated migration file to get an idea about what Prisma Migrate is doing behind the scenes:</p>
<pre><code class="lang-bash">-- prisma/migrations/20220528101323_init/migration.sql

CREATE TABLE <span class="hljs-string">"Recipe"</span> (
    <span class="hljs-string">"id"</span> SERIAL NOT NULL,
    <span class="hljs-string">"title"</span> TEXT NOT NULL,
    <span class="hljs-string">"description"</span> TEXT,
    <span class="hljs-string">"ingredients"</span> TEXT NOT NULL,
    <span class="hljs-string">"instructions"</span> TEXT NOT NULL,
    <span class="hljs-string">"createdAt"</span> TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    <span class="hljs-string">"updatedAt"</span> TIMESTAMP(3) NOT NULL,

    CONSTRAINT <span class="hljs-string">"Recipe_pkey"</span> PRIMARY KEY (<span class="hljs-string">"id"</span>)
);

-- CreateIndex
CREATE UNIQUE INDEX <span class="hljs-string">"Recipe_title_key"</span> ON <span class="hljs-string">"Recipe"</span>(<span class="hljs-string">"title"</span>);
</code></pre>
<p>This migration file contains the SQL commands necessary to create the <code>Recipe</code> table. It also contains the SQL commands necessary to create the <code>title</code> field, which is a unique field. This ensures that the <code>title</code> field is unique, preventing duplicate recipes from being created.</p>
<h2 id="heading-how-to-seed-the-database">How to Seed the Database</h2>
<p>Now that we've migrated our database, we're ready to seed it with some test data. This will allow us to test our application without having to manually create recipes.</p>
<p>Firstly, create a seed file called <code>prisma/seed.ts</code>. This file will contain the dummy data and queries needed to seed your database.</p>
<p>Open the terminal and run the following command:</p>
<pre><code class="lang-bash">touch prisma/seed.ts
</code></pre>
<p>This command creates a new <code>prisma/seed.ts</code> file in your project's root directory.</p>
<p>Next, populate this file with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// prisma/seed.ts</span>
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

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

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// create two dummy recipes</span>
  <span class="hljs-keyword">const</span> recipe1 = <span class="hljs-keyword">await</span> prisma.recipe.upsert({
    where: { title: <span class="hljs-string">'Spaghetti Bolognese'</span> },
    update: {},
    create: {
      title: <span class="hljs-string">'Spaghetti Bolognese'</span>,
      description: <span class="hljs-string">'A classic Italian dish'</span>,
      ingredients:
        <span class="hljs-string">'Spaghetti, minced beef, 
        tomato sauce, onions, garlic, olive oil, salt, pepper'</span>,
      instructions:
        <span class="hljs-string">'1. Cook the spaghetti. 2. Fry the minced beef. 3.
        Add the tomato sauce to the beef.
        4. Serve the spaghetti with the sauce.'</span>
    }
  });

  <span class="hljs-keyword">const</span> recipe2 = <span class="hljs-keyword">await</span> prisma.recipe.upsert({
    where: { title: <span class="hljs-string">'Chicken Curry'</span> },
    update: {},
    create: {
      title: <span class="hljs-string">'Chicken Curry'</span>,
      description: <span class="hljs-string">'A spicy Indian dish'</span>,
      ingredients:
        <span class="hljs-string">'Chicken, curry powder, onions, garlic, 
        coconut milk, olive oil, salt, pepper'</span>,
      instructions:
        <span class="hljs-string">'1. Fry the chicken. 2. Add the curry powder to the
        chicken. 3. Add the coconut milk.
        4. Serve the curry with rice.'</span>
    }
  });

  <span class="hljs-built_in">console</span>.log({ recipe1, recipe2 });
}

<span class="hljs-comment">// execute the main function</span>
main()
  .catch(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(e);
    process.exit(<span class="hljs-number">1</span>);
  })
  .finally(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// close Prisma Client at the end</span>
    <span class="hljs-keyword">await</span> prisma.$disconnect();
  });
</code></pre>
<p>This file contains the dummy data and queries needed to seed your database. Let's break it down:</p>
<ul>
<li><code>import { PrismaClient } from '@prisma/client';</code>: This imports the Prisma Client, which is used to send queries to the database.</li>
<li><code>const prisma = new PrismaClient();</code>: This initializes the Prisma Client, allowing us to send queries to the database.</li>
<li><code>async function main() { ... }</code>: This is the main function that contains the dummy data and queries needed to seed your database.</li>
<li><code>const recipe1 = await prisma.recipe.upsert({ ... });</code>: This creates a new recipe. It uses the <code>upsert</code> method, which creates a new recipe if it doesn't exist, or updates the existing recipe if it does.</li>
<li><code>const recipe2 = await prisma.recipe.upsert({ ... });</code>: This creates a new recipe. It uses the <code>upsert</code> method, which creates a new recipe if it doesn't exist, or updates the existing recipe if it does.</li>
<li><code>console.log({ recipe1, recipe2 });</code>: This logs the newly created recipes to the console.</li>
<li><code>main().catch((e) =&gt; { ... });</code>: This executes the main function and catches any errors that occur.</li>
<li><code>await prisma.$disconnect();</code>: This closes the Prisma Client at the end.</li>
</ul>
<p>Now before we can seed our database, we need add a script to our <code>package.json</code> file. Open the <code>package.json</code> file and add the following script:</p>
<pre><code class="lang-json">

<span class="hljs-comment">// package.json</span>

<span class="hljs-comment">// ...</span>
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"jest"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-comment">// pasting the prisma script here</span>
  <span class="hljs-string">"prisma"</span>: {
    <span class="hljs-attr">"seed"</span>: <span class="hljs-string">"ts-node prisma/seed.ts"</span>
  }
</code></pre>
<p>The seed command will execute the <code>prisma/seed.ts</code> script that you previously defined. This command should work automatically because ts-node is already installed as a dev dependency in your <code>package.json</code>.</p>
<p>Now that we've defined our seed script, we're ready to seed the database. To seed your database, execute the following command:</p>
<pre><code class="lang-bash">npx prisma db seed
</code></pre>
<p>This command will seed your database with the dummy data defined in your <code>prisma/seed.ts</code> file. If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-ts">Running seed command <span class="hljs-string">`ts-node prisma/seed.ts`</span> ...
{
  recipe1: {
    id: <span class="hljs-number">1</span>,
    title: <span class="hljs-string">'Spaghetti Bolognese'</span>,
    description: <span class="hljs-string">'A classic Italian dish'</span>,
    ingredients: <span class="hljs-string">'Spaghetti, minced beef, tomato sauce, onions, garlic, olive oil, salt, pepper'</span>,
    instructions: <span class="hljs-string">'1. Cook the spaghetti. 2. Fry the minced beef. 3. Add the tomato sauce to the beef. 4. Serve the spaghetti with the sauce.'</span>,
    createdAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.133</span>Z,
    updatedAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.133</span>Z
  },
  recipe2: {
    id: <span class="hljs-number">2</span>,
    title: <span class="hljs-string">'Chicken Curry'</span>,
    description: <span class="hljs-string">'A spicy Indian dish'</span>,
    ingredients: <span class="hljs-string">'Chicken, curry powder, onions, garlic, coconut milk, olive oil, salt, pepper'</span>,
    instructions: <span class="hljs-string">'1. Fry the chicken. 2. Add the curry powder to the chicken. 3. Add the coconut milk. 4. Serve the curry with rice.'</span>,
    createdAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.155</span>Z,
    updatedAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.155</span>Z
  }
}

The seed command has been executed.
</code></pre>
<p>Congratulations 🎉. You now have a fully functional database with dummy data.</p>
<h2 id="heading-how-to-create-a-prisma-service">How to Create a Prisma Service</h2>
<p>Now that we've set up Prisma, we're ready to create a Prisma service. This service will act as a wrapper around the Prisma Client, making it easy to send queries to the database.</p>
<p>The Nest CLI gives you an easy way to generate modules and services directly from the CLI. Run the following command in your terminal:</p>
<pre><code class="lang-bash">
npx nest generate module prisma
npx nest generate service prisma
</code></pre>
<p>Note that the <code>generate</code> command can be shortened to <code>g</code>. So, you can also run the following command:</p>
<pre><code class="lang-bash">
npx nest g module prisma
npx nest g service prisma
</code></pre>
<p>This command generates a new module called <code>prisma</code> and a new service called <code>prisma</code>. It also imports the <code>PrismaModule</code> into the <code>AppModule</code>.</p>
<p>So you should see something like this:</p>
<pre><code class="lang-bash">
  src/prisma/prisma.service.spec.ts
  src/prisma/prisma.service.ts
  src/prisma/prisma.module.ts
</code></pre>
<p>Note: In some cases, you may need to restart your server for the changes to take effect.</p>
<p>Next, open the <code>prisma.service.ts</code> file and replace the contents with the following:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/prisma/prisma.service.ts</span>

<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaService <span class="hljs-keyword">extends</span> PrismaClient {}
</code></pre>
<p>This service is a wrapper around the Prisma Client, making it easy to send queries to the database. It's also a NestJS provider, which means it can be injected into other modules.</p>
<p>Next, open the <code>prisma.module.ts</code> file and replace the contents with the following:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/prisma/prisma.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./prisma.service'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [PrismaService],
  <span class="hljs-built_in">exports</span>: [PrismaService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaModule {}
</code></pre>
<p><strong>Note:</strong> The <code>PrismaModule</code> is a NestJS module that imports the <code>PrismaService</code>, making it readily available for use across other modules in your application. This setup allows seamless integration of the Prisma service throughout your project.</p>
<p>Congratulations 🎉! You've successfully set up your Prisma service.</p>
<p>Before we dive into writing our application logic, let's set up Swagger. Swagger is an industry-standard tool for designing, building, and documenting RESTful APIs. It empowers developers to create elegant and comprehensive API documentation effortlessly.</p>
<h2 id="heading-how-to-set-up-swagger">How to Set Up Swagger</h2>
<p>To configure Swagger, we'll leverage the <code>@nestjs/swagger</code> package. This package offers a suite of decorators and methods specifically designed to generate Swagger documentation.</p>
<p>To install this package, run the following command:</p>
<pre><code class="lang-bash">npm install --save @nestjs/swagger swagger-ui-express
</code></pre>
<p>This command adds the <code>@nestjs/swagger</code> package as a dependency in your project. It also installs the <code>swagger-ui-express</code> package, which serves the Swagger UI.</p>
<p>Next, navigate to the <code>main.ts</code> file and append the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/main.ts</span>

<span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
<span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;
<span class="hljs-keyword">import</span> { SwaggerModule, DocumentBuilder } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;

<span class="hljs-comment">// Define the bootstrap function</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Create a NestJS application instance by passing the AppModule to the NestFactory</span>
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);

  <span class="hljs-comment">// Use DocumentBuilder to create a new Swagger document configuration</span>
  <span class="hljs-keyword">const</span> config = <span class="hljs-keyword">new</span> DocumentBuilder()
    .setTitle(<span class="hljs-string">'Recipes API'</span>) <span class="hljs-comment">// Set the title of the API</span>
    .setDescription(<span class="hljs-string">'Recipes API description'</span>) <span class="hljs-comment">// Set the description of the API</span>
    .setVersion(<span class="hljs-string">'0.1'</span>) <span class="hljs-comment">// Set the version of the API</span>
    .build(); <span class="hljs-comment">// Build the document</span>

  <span class="hljs-comment">// Create a Swagger document using the application instance and the document configuration</span>
  <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = SwaggerModule.createDocument(app, config);

  <span class="hljs-comment">// Setup Swagger module with the application instance and the Swagger document</span>
  SwaggerModule.setup(<span class="hljs-string">'api'</span>, app, <span class="hljs-built_in">document</span>);

  <span class="hljs-comment">// Start the application and listen for requests on port 3000</span>
  <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
}

<span class="hljs-comment">// Call the bootstrap function to start the application</span>
bootstrap();
</code></pre>
<p>This code initializes Swagger and generates the Swagger documentation. Let's break it down:</p>
<ul>
<li><code>const config = new DocumentBuilder() ... .build();</code>: This creates a new Swagger document builder. It sets the title, description, and version of the Swagger document. It also builds the Swagger document.</li>
<li><code>const document = SwaggerModule.createDocument(app, config);</code>: This creates a new Swagger document. It uses the Swagger document builder to generate the Swagger document.</li>
<li><code>SwaggerModule.setup('api', app, document);</code>: This sets up the Swagger UI. It uses the Swagger document to generate the Swagger UI.</li>
</ul>
<p>While the application is running, open your browser and navigate to <code>http://localhost:3000/api</code>. You should see the Swagger UI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Swager-first-look.png" alt="Swagger UI " width="600" height="400" loading="lazy">
<em>The initial view of the Swagger UI after successful setup.</em></p>
<p>Now that we've set up Swagger, we're ready to start building our REST API.</p>
<h2 id="heading-how-to-implement-crud-operations-for-the-recipe-model">How to Implement CRUD Operations for the Recipe Model</h2>
<p>In this section we'll implement the CRUD operations for the <code>Recipe</code> model. We'll start by generating the REST resources for the <code>Recipe</code> model. Then we'll add the Prisma Client to the <code>Recipe</code> module. Finally, we'll implement the CRUD operations for the <code>Recipe</code> model.</p>
<h3 id="heading-how-to-generate-rest-resources-with-nestjs-cli">How to Generate REST Resources with NestJS CLI</h3>
<p>Before we can implement the CRUD operations for the <code>Recipe</code> model, we need to generate the REST resources for the <code>Recipe</code> model. This will create the boilerplate code for the <code>Recipe</code> module, controller, service, and DTOs. </p>
<p>To generate the REST resources for the <code>Recipe</code> model, execute the following command:</p>
<pre><code class="lang-bash">
npx nest generate resource recipe
</code></pre>
<p>And it will ask you what type of API you want to generate. So now we will select the <code>REST API</code> .</p>
<p>Check out the below image for reference:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Generating-CRUD.png" alt="REST API  " width="600" height="400" loading="lazy">
<em>Selecting REST API when creating the CRUD operations using the Nest CLI</em></p>
<p>This command will generate the following files:</p>
<pre><code class="lang-bash">
CREATE src/recipe/recipe.controller.ts (959 bytes)
CREATE src/recipe/recipe.controller.spec.ts (596 bytes)
CREATE src/recipe/recipe.module.ts (264 bytes)
CREATE src/recipe/recipe.service.ts (661 bytes)
CREATE src/recipe/recipe.service.spec.ts (478 bytes)
CREATE src/recipe/dto/create-recipe.dto.ts (33 bytes)
CREATE src/recipe/dto/update-recipe.dto.ts (176 bytes)
CREATE src/recipe/entities/recipe.entity.ts (24 bytes)
UPDATE src/app.module.ts (385 bytes)
</code></pre>
<p>If you open the Swagger API page again, you should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/swagger-pplo--after-crating-crud.png" alt="SWagger UI  " width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the newly created CRUD operations.</em></p>
<p>The swagger page now has a new section called <code>Recipe API</code> . This section contains the REST resources for the <code>Recipe</code> model.</p>
<p>Now when you open Swagger you will see something like this:</p>
<ul>
<li><code>POST /recipes</code>: Create a new recipe.</li>
<li><code>GET /recipes</code>: Retrieve all recipes.</li>
<li><code>GET /recipes/{id}</code>: Retrieve a specific recipe by its ID.</li>
<li><code>PATCH /recipes/{id}</code>: Update a specific recipe by its ID.</li>
<li><code>DELETE /recipes/{id}</code>: Delete a specific recipe by its ID.</li>
</ul>
<h3 id="heading-how-to-add-prismaclient-to-the-recipe-module">How to Add <code>PrismaClient</code> to the Recipe Module</h3>
<p>Now that we've generated the REST resources for the <code>Recipe</code> model, we're ready to add the Prisma Client to the <code>Recipe</code> module. This will allow us to send queries to the database.</p>
<p>Firstly, open the <code>recipe.module.ts</code> file and add the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.module.ts</span>

<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { RecipeService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./recipe.service'</span>;
<span class="hljs-keyword">import</span> { RecipeController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./recipe.controller'</span>;
<span class="hljs-keyword">import</span> { PrismaModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'../prisma/prisma.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [PrismaModule],
  controllers: [RecipeController],
  providers: [RecipeService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RecipeModule {}
</code></pre>
<p>So now we have imported the <code>PrismaModule</code> and added it to the <code>imports</code> array. This will make the <code>PrismaService</code> available to the <code>RecipeService</code>.</p>
<p>Next, open the <code>recipe.service.ts</code> file and add the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-keyword">import</span> { Body, Injectable, Post } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateRecipeDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create--recipe.dto'</span>;
<span class="hljs-keyword">import</span> { UpdateRecipeDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update--recipe.dto'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/prisma/prisma.service'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RecipesService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> prisma: PrismaService</span>) {}

  <span class="hljs-comment">//  rest of the code</span>
}
</code></pre>
<p>So now we have defined the <code>prisma</code> service as a private property of the <code>RecipeService</code> class. This will allow us to access the <code>PrismaService</code> from within the <code>RecipeService</code> class. So now we use the <code>prisma</code> service to perform the CRUD operations.</p>
<p>Sine we have defined the service for the Recipe model, we're ready to implement the CRUD operations for the Recipe model.</p>
<h3 id="heading-how-to-define-the-get-recipes-endpoint">How to Define the <code>GET /recipes</code> Endpoint</h3>
<p>Let's kickstart our journey into crafting API endpoints by defining the <code>GET /recipes</code> endpoint. This endpoint will serve as a gateway to fetch all the recipes stored in our database.</p>
<p>In your <code>recipes.controller.ts</code> file, you'll find a method named <code>findAll</code>. This method, as the name suggests, is responsible for fetching all the recipes. Here's how we'll define it:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// Other code...</span>

<span class="hljs-meta">@Get</span>()
<span class="hljs-keyword">async</span> findAll() {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipeService.findAll();
}

<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>In the above code:</p>
<ul>
<li>The <code>@Get()</code> decorator maps the <code>findAll</code> method to the <code>GET /recipes</code> endpoint.</li>
<li>The <code>findAll</code> method invokes the <code>findAll</code> method of the <code>recipeService</code>, which retrieves all the recipes from the database.</li>
</ul>
<p>As we've previously seen, the <code>Controller</code> is the heart of our application's logic. In this context, we're aiming to implement a <code>findAll</code> method that fetches all recipes from our database. To accomplish this, we'll harness the power of Prisma's services within our <code>recipe.service.ts</code> file.</p>
<p>When you open the <code>recipe.service.ts</code> file you will see something like this :</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// Other code...</span>
<span class="hljs-comment">// src/recipes/recipes.service.ts</span>
 findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action returns all recipe`</span>;
  }
<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>NOW we will replace the <code>findAll</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// Other code...</span>

<span class="hljs-keyword">async</span> findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.findMany();
}
<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>In the above snippet:</p>
<ul>
<li>The <code>findAll</code> method utilizes Prisma's <code>findMany</code> function to retrieve all recipes from the database.</li>
<li>The <code>await</code> keyword is not necessary here because the <code>async</code> function implicitly wraps the returned value in a Promise.</li>
</ul>
<p>We've now successfully implemented the service method that our <code>findAll</code> controller will use to fetch all recipes.</p>
<p>Given that we already have seed data in our database, opening Swagger should allow us to retrieve all the recipes. Here's what you can expect to see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/get-all-recipe-swagger.png" alt="Fetch All Recipes" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the result of the 'Fetch All Recipes' operation.</em></p>
<p>As depicted in the image above, our <code>GET /recipes</code> endpoint is functioning as expected, successfully fetching all recipes from our database. </p>
<p>This marks a significant milestone in our journey of building a robust recipe management system. Let's continue on and add some more features.</p>
<h3 id="heading-how-to-define-the-get-recipesid-endpoint">How to Define the <code>GET /recipes/{id}</code> Endpoint</h3>
<p>Let's now focus on the <code>GET /recipes/{id}</code> endpoint, which retrieves a specific recipe based on its ID. To implement this, we'll need to modify both the <code>controller</code> and the <code>service</code>.</p>
<p>First, navigate to the <code>recipes.controller.ts</code> file. Here, you'll find the <code>findOne</code> method, which is defined as follows:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipeService.findOne(+id);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Get(':id')</code> decorator maps to the <code>GET /recipes/{id}</code> endpoint.</li>
<li>The <code>findOne</code> method accepts an <code>id</code> parameter, which is extracted from the route parameters.</li>
</ul>
<p>Next, let's turn our attention to the <code>recipes.service.ts</code> file. Here, you'll find a placeholder <code>findOne</code> method:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// other code ...</span>
  findOne(id: <span class="hljs-built_in">number</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action returns a #<span class="hljs-subst">${id}</span> recipe`</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>We'll replace this placeholder with a method that fetches a recipe based on its <code>id</code>:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

findOne(id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.findUnique({
    where: { id },
  });
}
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>findOne</code> method takes an <code>id</code> as an argument and uses Prisma's <code>findUnique</code> function to retrieve the recipe with the corresponding <code>id</code>.</li>
</ul>
<p>With the recent modifications, you've unlocked the ability to fetch individual recipes by their ID.</p>
<p>To see this feature in action, navigate to your Swagger page. Here's a snapshot of what you can expect:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Get-by-id.png" alt="GET BY ID" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the result of the 'GET BY ID' operation.</em></p>
<p>Having achieved this milestone, we're ready to venture into creating our own recipes, adding to the existing ones in our database.</p>
<h3 id="heading-how-to-define-the-post-recipes-endpoint">How to Define the <code>POST /recipes</code> Endpoint</h3>
<p>The NestJS CLI has conveniently generated a <code>create</code> method for us when we created the resource for the <code>Recipe</code> model. Now, we need to implement the logic for this method in the <code>recipe.service.ts</code> file.</p>
<p>First, let's look at the <code>create</code> method in the <code>recipe.controller.ts</code> file:<br>We will see something like this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Post</span>()
create(<span class="hljs-meta">@Body</span>() createRecipeDto: CreateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipesService.create(createRecipeDto);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Post()</code> decorator maps the method to the <code>POST /recipes</code> endpoint.</li>
<li>The <code>create</code> method accepts a <code>createRecipeDto</code> parameter, which is extracted from the request body.</li>
</ul>
<p>The NestJS CLI has thoughtfully provided us with DTO (Data Transfer Object) files within the <code>recipe</code> folder. One of these, <code>CreateRecipeDto</code>, will be our tool of choice for validating incoming client data.</p>
<p><strong>A Quick DTO Primer</strong>: If you're new to the concept of DTOs, they're essentially objects that carry data between processes. In the context of our application, we'll use DTOs to ensure the data we receive aligns with our expectations. If you're keen to delve deeper into DTOs, check out this comprehensive <a target="_blank" href="https://docs.nestjs.com/controllers#request-payloads">guide</a>.</p>
<p>Now, let's implement the <code>create</code> method in the <code>recipe.service.ts</code> file to interact with our database.</p>
<p>But before we proceed, let's harness the power of the DTO (Data Transfer Object) folder, generated by the Nest CLI, to model our data.</p>
<p>The <code>CreateRecipeDto</code> class, as shown below, is a prime example of a DTO. It's designed to validate incoming client data, ensuring it aligns with our expectations.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/dto/create-recipe.dto.ts</span>
<span class="hljs-keyword">import</span> { IsString, IsOptional } <span class="hljs-keyword">from</span> <span class="hljs-string">'class-validator'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateRecipeDto {
  <span class="hljs-meta">@IsString</span>()
  title: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsOptional</span>()
  <span class="hljs-meta">@IsString</span>()
  description?: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsString</span>()
  ingredients: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsString</span>()
  instructions: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>In this class, we're using the <code>class-validator</code> package to enforce data validation. This package offers a suite of decorators, such as <code>IsString</code> and <code>IsOptional</code>, which we've employed to validate the <code>title</code>, <code>description</code>, <code>ingredients</code>, and <code>instructions</code> fields. </p>
<p>With this setup, we can confidently ensure that these fields will always be strings, with <code>description</code> being optional.</p>
<p>Now, let's implement the <code>create</code> method in the <code>recipe.service.ts</code> file to interact with our database. When you open the <code>recipe.service.ts</code> file you will see something like this:</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
  create(createRecipeDto: CreateRecipeDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This action adds a new recipe'</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>create</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
create(createRecipeDto: CreateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.create({
    data: createRecipeDto,
  });
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>create</code> method uses Prisma's <code>create</code> function to add a new recipe to the database. The data for the new recipe is provided by the <code>createRecipeDto</code>.</li>
</ul>
<p>With these changes, you can now create new recipes in your swagger page. Here's what you can expect to see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Creating-POST.png" alt="Creating a Recipe" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the process of creating a new recipe.</em></p>
<p>As depicted in the image above, we've successfully added a third recipe to our collection. This demonstrates the effectiveness of our POST method in creating new recipes.</p>
<h3 id="heading-how-to-define-the-patch-recipesid-endpoint">How to Define the <code>PATCH /recipes/{id}</code> Endpoint</h3>
<p>Having implemented the endpoints to create and retrieve recipes, let's now focus on updating a recipe. We'll implement the <code>PATCH /recipes/{id}</code> endpoint, which updates a specific recipe based on its ID. This requires modifications in both the <code>controller</code> and the <code>service</code>.</p>
<p>In the <code>recipes.controller.ts</code> file, locate the <code>update</code> method. This method is mapped to the <code>PATCH /recipes/{id}</code> endpoint:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Patch</span>(<span class="hljs-string">':id'</span>)
update(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>, <span class="hljs-meta">@Body</span>() updateRecipeDto: UpdateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipesService.update(+id, updateRecipeDto);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Patch(':id')</code> decorator maps the method to the <code>PATCH /recipes/{id}</code> endpoint.</li>
<li>The <code>update</code> method accepts two parameters: <code>id</code> (extracted from the route parameters) and <code>updateRecipeDto</code> (extracted from the request body).</li>
</ul>
<p>Next, let's implement the <code>update</code> method in the <code>recipe.service.ts</code> file. When you open the <code>recipe.service.ts</code> file, you will see something like this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
  update(id: <span class="hljs-built_in">number</span>, updateRecipeDto: UpdateRecipeDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action updates a #<span class="hljs-subst">${id}</span> recipe`</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>update</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

update(id: <span class="hljs-built_in">number</span>, updateRecipeDto: UpdateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.update({
    where: { id },
    data: updateRecipeDto,
  });
}
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>update</code> method uses Prisma's <code>update</code> function to update the recipe in the database. The <code>where</code> clause specifies the recipe to update (based on <code>id</code>), and the <code>data</code> clause specifies the new data for the recipe (provided by <code>updateRecipeDto</code>).</li>
</ul>
<p>With the recent modifications, we've unlocked the ability to update individual recipes by their ID.</p>
<p>Let's put this new feature to the test by updating the recipe with an ID of 3.</p>
<p>Here's a snapshot of the current state of the recipe:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/by-id3.png" alt="Current Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the current data of a specific recipe.</em></p>
<p>As depicted above, this is the existing data for the recipe we're about to update.</p>
<p>After executing the update operation, here's how our recipe transforms:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/after-updating-id-3-response.png" alt="Updated Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the updated data of a specific recipe after modification.</em></p>
<p>As you can see, our update operation has successfully modified the recipe, demonstrating the effectiveness of our newly implemented feature.</p>
<p>Let's now turn our attention to deleting recipes.</p>
<h3 id="heading-how-to-define-the-delete-recipesid-endpoint">How to Define the <code>DELETE /recipes/{id}</code> Endpoint</h3>
<p>Having successfully defined the <code>GET</code>, <code>POST</code>, and <code>PATCH</code> endpoints, our next task is to implement the <code>DELETE /recipes/{id}</code> endpoint. This endpoint will let us remove a specific recipe using its ID. As with the previous endpoints, we'll need to make modifications in both the <code>controller</code> and the <code>service</code>.</p>
<p>In the <code>recipes.controller.ts</code> file, we have a <code>remove</code> method. This method is mapped to the <code>DELETE /recipes/{id}</code> endpoint:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipesService.remove(id);
}
</code></pre>
<p>In this updated code:</p>
<ul>
<li>The <code>@Delete(':id')</code> decorator maps the method to the <code>DELETE /recipes/{id}</code> endpoint.</li>
<li>The <code>remove</code> method accepts an <code>id</code> parameter, which is extracted from the route parameters and parsed to a number using <code>ParseIntPipe</code>.</li>
</ul>
<p>Next, let's implement the <code>remove</code> method in the <code>recipe.service.ts</code> file. Now with the <code>remove</code> method you see this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// other code ...</span>
 <span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
  remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipeService.remove(+id);
  }

  <span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>remove</code> method with this code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>


<span class="hljs-comment">// other code </span>
<span class="hljs-keyword">async</span> remove(id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.recipe.delete({
    where: { id },
  });
}

<span class="hljs-comment">// other code ..</span>
</code></pre>
<p>In this code, the <code>remove</code> method uses Prisma's <code>delete</code> function to remove the recipe with the specified <code>id</code> from the database.</p>
<p>In this code:</p>
<ul>
<li>The <code>remove</code> method uses Prisma's <code>delete</code> function to remove the recipe with the corresponding <code>id</code> from the database.</li>
</ul>
<p>With these changes, you can now delete individual recipes by their ID. Check the Swagger page to see the updated API documentation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/delet-by-id.png" alt="Delete Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the process of deleting a specific recipe.</em></p>
<h2 id="heading-summary-and-final-remarks">Summary and Final Remarks</h2>
<p>In this handbook, we've journeyed through the process of building a REST API using NestJS and Prisma. </p>
<p>We started by setting up a NestJS project, configuring a PostgreSQL database using Docker, and integrating Prisma.</p>
<p>We then dove into the heart of our application, creating a <code>Recipe</code> model and implementing CRUD operations for it. This involved generating RESTful routes, integrating the Prisma Client into our <code>Recipe</code> service, and crafting the logic for each operation.</p>
<p>This guide serves as a solid foundation for your future projects. Feel free to expand upon it, adding more features and functionalities to suit your needs. Thank you for following along, and happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform CRUD Operations – JavaScript and SQL Example ]]>
                </title>
                <description>
                    <![CDATA[ For the most part, interactive website architectures will involve generating or dispensing data of one sort or another. You can certainly use HTML forms to collect user input. But the kind of web form that's described here will only take you so far. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-perform-crud-operations-js-and-sql/</link>
                <guid isPermaLink="false">66b995f17bb37b73c3f3c4e5</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Thu, 03 Aug 2023 20:41:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/5f9ca0b7740569d1a4ca4a58.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For the most part, interactive website architectures will involve generating or dispensing data of one sort or another. You can certainly use HTML forms to collect user input. But the kind of web form <a target="_blank" href="https://www.freecodecamp.org/news/creating-html-forms/">that's described here</a> will only take you so far. </p>
<p>What we really need is a way to reliably store and manipulate our data within the application environment. </p>
<p>In this article, I'm going to show you how to connect a back end database to your data collection process. The plan involves tossing some HTML, JavaScript, and the tiny database engine SQLite into a bowl, mixing vigorously, and seeing what comes out. </p>
<p>This article comes from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-web-development-essentials-exam-study-guide/?referralCode=C92570BCBB38302A9257">my Complete LPI Web Development Essentials Study Guide course</a>. If you'd like, you can follow the video version here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/yf2RJmpMEiI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>As you may already know, the SQL in SQLite stands for <em>structured query language</em>. This means that the syntax you'll use for interacting with a SQLite database will closely parallel how you'd do it with databases like MariaDB, Amazon Aurora, Oracle, or Microsoft's SQL Server. If you've got experience with any of those, you'll be right at home here.</p>
<p>Why are we going to use SQLite here? Because it's a very popular choice for the kind of work you're likely to undertake in a web environment. </p>
<p>You'll need to create a new directory on your machine along with some files with JavaScript code. We'll learn how to create, modify, and delete records in a SQLite database. </p>
<p>I could incorporate all those actions into a single file, of course, but I think breaking them out into multiple files will make it easier to understand what's going on.</p>
<h2 id="heading-connecting-to-a-database-and-creating-a-table">Connecting to a Database and Creating a Table</h2>
<p>Here's what the first file will look like:</p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();

<span class="hljs-comment">// Create/connect to the database</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);

<span class="hljs-comment">// Create a table</span>
db.run(<span class="hljs-string">`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    age INTEGER
)`</span>);

<span class="hljs-comment">// Insert data</span>
<span class="hljs-keyword">const</span> insertQuery = <span class="hljs-string">`INSERT INTO users (name, age) VALUES (?, ?)`</span>;
<span class="hljs-keyword">const</span> name = <span class="hljs-string">'Trevor'</span>;
<span class="hljs-keyword">const</span> age = <span class="hljs-number">5</span>;
db.run(insertQuery, [name, age], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Inserted data with id <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastID}</span>`</span>);
    }
});

<span class="hljs-comment">// Close the database connection</span>
db.close();
</code></pre><p>We begin by loading the sqlite3 module as <code>sqlite3</code> and then creating the <code>db</code> variable to represent our new database instance. The database will be called <code>mydatabase.db</code>. </p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);
</code></pre><p>If there isn't a database using that name in our local directory, the code will create one, otherwise it'll just connect to the one that's there already.</p>
<p>Since this is our first run, I'll create a new table within the <code>mydatabase.db</code> database. There will be three keys in our table: <code>id</code>, <code>name</code>, and <code>age</code>. </p>
<pre><code>db.run(<span class="hljs-string">`CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    age INTEGER
)`</span>);
</code></pre><p>As you can see, <code>id</code> will be the primary key that we'll use to reference individual records. </p>
<p>We defined the data type of each key: integer, text and, again, integer. This definition is something we only need to do once. But we do want to get it right, because changing it later, after we've already added data, can be tricky.</p>
<h2 id="heading-inserting-new-data-into-a-table">Inserting New Data into a Table</h2>
<p>In this section, we'll will add a new record to the table using the SQL <code>INSERT</code> command.</p>
<pre><code><span class="hljs-keyword">const</span> insertQuery = <span class="hljs-string">`INSERT INTO users (name, age) VALUES (?, ?)`</span>;
<span class="hljs-keyword">const</span> name = <span class="hljs-string">'Trevor'</span>;
<span class="hljs-keyword">const</span> age = <span class="hljs-number">5</span>;
db.run(insertQuery, [name, age], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Inserted data with id <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastID}</span>`</span>);
    }
});
</code></pre><p>You'll probably discover that official SQL documentation always capitalizes key syntax terms like <code>INSERT</code> and <code>SELECT</code>. That's a useful best practice, but it's not actually necessary. As a rule, I'm way too lazy to bother.</p>
<p>The query itself is templated as <code>insertQuery</code>, with the <code>name</code> and <code>age</code> details added as constants in the lines that follow. </p>
<p>The <code>db.run</code> method, using the <code>insertQuery</code> constant and those two values (<code>name</code> and <code>age</code>) as attributes, is then executed. Based on the success or failure of the operation, log messages will be generated.</p>
<p>But hang on for a moment. What's with those question marks after declaring <code>insertQuery</code>? And why did we need to break this process into two parts? </p>
<p>This is actually an important security practice known as an escape variable. With this in place, when the <code>db.run()</code> method executes the prepared statement, it'll automatically handle the escaping of the variable value, preventing SQL injection.</p>
<p>Lastly, we close down the connection:</p>
<pre><code>db.close();
</code></pre><h2 id="heading-modifying-data">Modifying Data</h2>
<p>Now let's see how the "modify" code works. Like before, we create a SQLite3 constant and then connect to our database. </p>
<p>This time, however, our table already exists, so we can go straight to the "modify" section.</p>
<pre><code><span class="hljs-keyword">const</span> sqlite3 = <span class="hljs-built_in">require</span>(<span class="hljs-string">'sqlite3'</span>).verbose();

<span class="hljs-comment">// Create/connect to the database</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> sqlite3.Database(<span class="hljs-string">'mydatabase.db'</span>);

<span class="hljs-comment">// Modify data</span>
<span class="hljs-keyword">const</span> updateQuery = <span class="hljs-string">`UPDATE users SET age = ? WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> updatedAge = <span class="hljs-number">30</span>;
<span class="hljs-keyword">const</span> updatedName = <span class="hljs-string">'name2'</span>;
db.run(updateQuery, [updatedAge, updatedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Modified <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});

<span class="hljs-comment">// Close the database connection</span>
db.close();
</code></pre><p>The pattern is similar. We define an <code>updateQuery</code> method to <code>UPDATE</code> a record that we'll define. This operation will change the <code>age</code> value for an entry whose name equals <code>Trevor</code>. </p>
<p>You may recall that Trevor's age was earlier listed as 25. We're going to update that to 30. Everything else will work the same as before, including closing the connection when we're done.</p>
<p>This section of code from the third file will delete a record:</p>
<pre><code><span class="hljs-keyword">const</span> deleteQuery = <span class="hljs-string">`DELETE FROM users WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> deletedName = <span class="hljs-string">'name1'</span>;
db.run(deleteQuery, [deletedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Deleted <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});
</code></pre><p>The code above will delete the record where the name equals <code>Trevor</code>.</p>
<p>You can run any of those files using the <code>node</code>  command. But you should first make sure that you've installed the <code>sqlite3</code> module:</p>
<pre><code>$ npm install sqlite3
</code></pre><p>Next I'll use <code>node</code> to run the first file (that you could choose to call <code>db.js</code>). </p>
<pre><code>$ node db.js
Inserted data <span class="hljs-keyword">with</span> id <span class="hljs-number">1</span>
</code></pre><p>We'll see that a new record has been successfully inserted. If you list the directory contents, you'll also see that a new <code>mydatabase.db</code> file has been created.</p>
<p>You can always manually log into sqlite3 to see how things might have changed. I'll reference the <code>mydatabase.db</code> file so we can open it up right away. </p>
<pre><code>$ sqlite3 mydatabase.db
</code></pre><p>Typing <code>.tables</code> within the SQLite interface will list all the existing tables in this database. In our case, it'll be the <code>users</code> table we created. </p>
<pre><code>sqlite&gt; .tables
users
sqlite&gt;
</code></pre><p>Now I'll use the SQL <code>select</code> command to display a record. Here I'll use the asterisk to represent all records and specify the <code>users</code> table. </p>
<pre><code>sqlite&gt; SELECT * FROM users;
<span class="hljs-number">1</span>|Trevor|<span class="hljs-number">25</span>
sqlite&gt;
</code></pre><p>We can see that record <code>1</code> containing <code>Trevor</code> who is 25 years old has been created. Great!</p>
<p>Finally, we can run the <code>delete</code> code which should remove Trevor altogether:</p>
<pre><code><span class="hljs-keyword">const</span> deleteQuery = <span class="hljs-string">`DELETE FROM users WHERE name = ?`</span>;
<span class="hljs-keyword">const</span> deletedName = <span class="hljs-string">'Trevor'</span>;
db.run(deleteQuery, [deletedName], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Deleted <span class="hljs-subst">${<span class="hljs-built_in">this</span>.changes}</span> row(s)`</span>);
    }
});
</code></pre><p>I should note that the <code>db.run</code> and <code>db.close</code> format I used for those methods can also be referred to as <code>Database.run()</code>, and <code>database.close()</code>. It's just a matter of preference - or, in my case, laziness. I'm a Linux admin, after all, and the very best admins are, in principle, lazy.</p>
<h2 id="heading-summary">Summary</h2>
<p>We've seen how use JavaScript to connect to a back end database, create a new table, and then add, modify, and delete records in that table. And we seem to have gotten away with it, too! </p>
<p>Now try this on your own computer. But play around with the values. Even better: build something practical.</p>
<p><em>This article comes from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-web-development-essentials-exam-study-guide/?referralCode=C92570BCBB38302A9257">my Complete LPI Web Development Essentials Study Guide course</a>.</em> <em>And there's much more technology goodness available at <a target="_blank" href="https://bootstrap-it.com/">bootstrap-it.com</a></em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a CRUD Command Line Application With Node.js ]]>
                </title>
                <description>
                    <![CDATA[ By Njoku Samson Ebere If you're looking for a tutorial to teach you the basics of Nodejs and the command line, you're in the right place.   You can use JavaScript to build almost any software (web, mobile, bots, and so on). The reason is that compute... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-command-line-application-with-nodejs/</link>
                <guid isPermaLink="false">66d84fa4c15439a8d5631e6d</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 06 Feb 2023 15:59:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/pexels-hitesh-choudhary-1261427.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Njoku Samson Ebere</p>
<p>If you're looking for a tutorial to teach you the basics of <a target="_blank" href="https://nodejs.org/en/">Nodejs</a> and the command line, you're in the right place.  </p>
<p>You can use JavaScript to build almost any software (web, mobile, bots, and so on). The reason is that computers no longer depend on browsers only to understand JavaScript code. Check out this article to see <a target="_blank" href="https://dev.to/ebereplenty/how-computers-understand-javascript-code-k1n">How Computers Understand JavaScript Code</a>. </p>
<p>Node.js is used to run backend applications that are written in JavaScript.   </p>
<p>I will teach you how to build a command line application that can read, write, edit, and delete data using Node.js. It will not require connecting to external databases like MySQL, MongoDB, Postgresql, and so on. See the project <a target="_blank" href="https://github.com/EBEREGIT/Nodejs_CLI_app">here</a>.  </p>
<p>By the end of the article, you should be able to set up a basic Node project, manipulate files, use modules, navigate promises, collect input, and so on.</p>
<p>I also added videos to enhance your learning.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You do not need any prior programming knowledge to understand this tutorial.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/RQ4b0Ui1-3o" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-how-the-finished-project-will-function">How the Finished Project Will Function</h2>
<p>The application that we are going to build will be able to do the following:</p>
<ul>
<li>Check if a database exists</li>
<li>Retrieve data from the database</li>
<li>Add new data to the database</li>
<li>Update database with new data</li>
<li>Remove data from the database</li>
</ul>
<h2 id="heading-how-to-install-node-and-npm">How to Install Node and NPM</h2>
<p>Please go to the <a target="_blank" href="https://nodejs.org/en/">Nodejs website</a> and download the one recommended for all users. Install it after the download is complete.</p>
<p>Use the command below to check if the installation was successful:</p>
<ul>
<li>For Node</li>
</ul>
<pre><code>node -v
</code></pre><ul>
<li>For npm</li>
</ul>
<pre><code>npm -v
</code></pre><p>The installation is successful if each command returns a version number.</p>
<h2 id="heading-how-to-setup-a-nodejs-project">How to Setup a  Node.js Project</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/8dlICKn-tQw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>The steps below will help you set up your project:  </p>
<p>Open your terminal or CMD and create the project directory:</p>
<pre><code>mkdir node_CLI_app
</code></pre><p>Navigate into the directory:</p>
<pre><code>cd node_CLI_app
</code></pre><p>Initialize the project:</p>
<pre><code>npm init
</code></pre><p>It will bring up some questions. Press the Enter button for every prompt.   </p>
<p>A new file (<code>package.json</code>) should have been added to your project directory. We will use the file to add external code (module) to the project.  </p>
<p>Add the following line before the closing curly brace (<code>}</code>) to enable ES6 import:</p>
<pre><code><span class="hljs-string">"type"</span>: <span class="hljs-string">"module"</span>
</code></pre><p>That completes the project setup!</p>
<h2 id="heading-how-to-install-dependencies">How to Install Dependencies</h2>
<p>You will recall that the <code>package.json</code> file is for adding external code to the project. This external code is also called Dependencies, Modules, or Packages. It's written by other programmers (usually free of charge) to help others build applications faster. You will find a lot of these on the <a target="_blank" href="https://www.npmjs.com/">npm website</a>.  </p>
<p>We need two (2) packages for this project: <a target="_blank" href="https://www.npmjs.com/package/inquirer">inquirer</a> and <a target="_blank" href="https://www.npmjs.com/package/uuid">uuid</a>. I will show you how to install them in this section.  </p>
<p>Installing of packages follows this pattern:</p>
<pre><code>npm install &lt;package_name&gt;
</code></pre><p>We can install more than one package at a time by separating the package names with a space:</p>
<pre><code>npm install &lt;package_name_1&gt; &lt;package_name_2&gt; &lt;package_name_3&gt;
</code></pre><p>The <code>install</code> command can be replaced with <code>i</code> for convenience.  </p>
<p>So run the following command to install the packages:</p>
<pre><code>npm i inquirer uuid
</code></pre><p>Your package.json file should have the following lines of code added to it when the installation is complete:</p>
<pre><code class="lang-javascript">
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"inquirer"</span>: <span class="hljs-string">"^9.1.4"</span>,
    <span class="hljs-string">"uuid"</span>: <span class="hljs-string">"^9.0.0"</span>
  }
</code></pre>
<p>The version numbers may differ, but that’s fine.</p>
<p>You will also notice that a file (<code>package.lock.json</code>) and a folder (<code>node_modules</code>) have been added. You do not have to worry about them. Just know that they help to manage the external code we just added.</p>
<p>That completes the installation of dependencies!</p>
<h2 id="heading-how-to-create-a-new-file-from-the-terminal">How to Create a New File from the Terminal</h2>
<p>You can create a file from the terminal using the following command:</p>
<ul>
<li>On Mac:</li>
</ul>
<pre><code>touch &lt;file_name&gt;
</code></pre><ul>
<li>On Windows:</li>
</ul>
<pre><code>echo.&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">file_name</span>&gt;</span></span>
</code></pre><p>You can also create more than one file at a time by separating the files with a space. That is how we will generate the files for this project:</p>
<pre><code>touch addData.js removeData.js retrieveData.js updateData.js queryDB.js dbFileCheck.js
</code></pre><p>Each of those files will play a unique role in the application.</p>
<ul>
<li><code>addData.js</code> adds data to the database. It also fabricates the database file if it doesn’t exist.</li>
<li><code>removeData.js</code> removes selected data.</li>
<li><code>retrieveData.js</code> fetches all data.</li>
<li><code>updateData.js</code> edits data.</li>
<li><code>queryDB.js</code> checks if a database exists and executes a function passed to it.</li>
<li><code>dbFileCheck.js</code> confirms if the database file has been created.</li>
</ul>
<p>There is one more file that we did not create: the database file (<code>db.json</code>). We will auto-generate it using our code.</p>
<h2 id="heading-how-to-check-if-a-file-exists">How to Check if a File Exists</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/V9dmEXCnY-8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Node.js provides a built-in module for manipulating files – <a target="_blank" href="https://nodejs.org/api/fs.html">file system</a> (fs). One of the methods that the module contains is the <code>existsSync</code> method. It returns <code>true</code> or <code>false</code> depending on if the file has been created. I will use that to check if the <code>db.json</code> file is in the project. See the code below:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
  <span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;  

  <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"File exists!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
</code></pre>
<p>The <code>exit</code> method terminates a process.</p>
<p>That is what we want to do in the <code>dbFileCheck.js</code> file. However, we want to invert the result by adding a <code>!</code> before the <code>fs.existsSync</code> method like this:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
  <span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;  

  <span class="hljs-keyword">if</span> (!fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"File does not exist!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
</code></pre>
<p>This will be necessary when building other functionalities like updating and deleting data. </p>
<p>So how will those files gain access to this code? It is through a modular structure. That entails bundling this code and making it accessible through other files in the project. The export command makes this possible:</p>
<pre><code><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> { exit } <span class="hljs-keyword">from</span> <span class="hljs-string">"process"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dbFileCheck</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (!fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Database is Empty. Create some data!"</span>);
    exit(<span class="hljs-number">1</span>);
  }
}
</code></pre><p>The code above puts the code in a function (<code>dbFileCheck</code>) and exports it using the <code>export</code> command. This function can now be imported and used in other files within this project.</p>
<p>Note that the <code>default</code> keyword is necessary for the first export from a file.</p>
<h2 id="heading-how-to-query-the-database">How to Query the Database</h2>
<p>Another method the <code>file system</code> has is the <code>readFile</code> method. It returns the content of any file passed to it. </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/ZmckWr9sH-w" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>The <code>readFile</code> method takes in two parameters: the file to be read and a callback function that returns the result of the operation.  </p>
<p>We will use the following code to retrieve data from our database:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
  <span class="hljs-keyword">if</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  }
  <span class="hljs-built_in">console</span>.log(data.toString());
});
</code></pre>
<p>The code above imports the file system module and tries to read the database file. If there is an error, it will return the error. If there are no errors, it will return the data it got. </p>
<p>The <code>.toString()</code> method attached to the data returned (<code>data.toString()</code>) is because the data retrieved is of the type <code>buffer</code> by default, which is not readable.</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074450995_Screenshot+2023-01-30+at+11.25.25.png" alt="Image" width="2654" height="107" loading="lazy">
<em>buffer output</em></p>
<p>Open your project in a code editor and paste that code into the <code>queryDB.js</code> file.  </p>
<p>Run the command below to see if it is working:</p>
<pre><code>node queryDB
</code></pre><p>The command above will execute every code in the <code>queryDB.js</code>. The <code>.js</code> extension is optional. It will run either way.</p>
<p>The result of that operation will be an error because we do not have the file.</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074558543_Screenshot+2023-01-30+at+11.28.47.png" alt="Image" width="1515" height="344" loading="lazy"></p>
<p>You can create the <code>db.json</code> file, add some content, and check the output.  </p>
<p>But we do not want our app to try to read the database file if it has not been generated. So use the <code>existsSync</code> method to check if the file has been created. See how I use it in the code below:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
        }
        <span class="hljs-built_in">console</span>.log(data.toString());
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No data available!"</span>);
    }
</code></pre>
<p>The code above checks if the file exists by passing the file name (<code>db.json</code>) to the <code>fs.existsSync</code> method. If it is true, then it reads the file. If it is false, it returns a string.</p>
<p>Now that we have that clean code, we want to make it even more robust.</p>
<p>Since we are building a CRUD application, we must have access to and keep track of the data returned. I have introduced a new variable in the code below to make that happen:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

    <span class="hljs-keyword">let</span> info = [];
    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
        }
        info = <span class="hljs-built_in">JSON</span>.parse(data.toString());
        <span class="hljs-built_in">console</span>.log(info);
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No data available!"</span>);
    }
</code></pre>
<p>The code above now has a variable, <code>info</code>. It keeps track of the data returned. I passed the data through the <code>JSON.parse</code> method to convert the data from string to array. </p>
<p>We can now manipulate the <code>info</code> as we deem fit. We have to export the code and accept a function to make this possible. That function will take the <code>info</code> variable as input and then use it as required.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">queryDB</span>(<span class="hljs-params">externalFunction</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">let</span> info = [];

    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      <span class="hljs-keyword">await</span> fs.readFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err, data</span>) </span>{
        info = <span class="hljs-built_in">JSON</span>.parse(data.toString());
        <span class="hljs-built_in">console</span>.log(info);

        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(err);
          <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-keyword">if</span> (externalFunction &amp;&amp; !err) {
          externalFunction(info);
          <span class="hljs-keyword">return</span>;
        }
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">if</span> (externalFunction) {
        externalFunction(info);
        <span class="hljs-keyword">return</span>;
      }
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Something Happened: <span class="hljs-subst">${error.message}</span>`</span>);
  }
}
</code></pre>
<p>This code takes in a function and executes it only if there are no errors. However, there will be one exception – when adding data. In that case, the database will be created.</p>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"><code>try…catch…</code></a> block helps pick out errors, and the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code></a> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>await</code></a> keywords are used when executing code that will take a long time to run.</p>
<p>The <code>queryDB.js</code> will no longer return any output when we execute the <code>node queryDB</code> command. But that is fine. We will trigger it from other files.</p>
<h2 id="heading-how-to-add-data-to-a-file">How to Add Data to a File</h2>
<p>In this section, I will teach you how to add data to the store. The file for this section is the <code>addData.js</code> file.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/vi0unBmidkE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>We will start by importing all necessary modules:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">"uuid"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
</code></pre>
<p>Next, create the boilerplate for the function:</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params">info</span>) </span>{
  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This is similar to what we have done before now. All the code we would write next will go into the <code>try…</code> block. The <code>info</code> array passed into the function is coming from the <code>queryDB</code> file.  </p>
<p>The first thing to do in the <code>try…</code> block is to collect the data to be stored. We will use <a target="_blank" href="https://www.npmjs.com/package/inquirer"><code>inquirer</code></a> to do that with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your name?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"number"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"phone"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your phone?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"list"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"age"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Are you an adult?"</span>,
        <span class="hljs-attr">choices</span>: [
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"Y"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Adult"</span> },
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"N"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Minor"</span> },
        ],
      },
    ]);
</code></pre>
<p>The <code>inquirer</code> package helps in building interactive command line interfaces. It contains a method called <code>prompt</code> used to ask for inputs. It takes an array of questions in object format. Each object must have the <code>name</code>, <code>type</code>, and <code>message</code> keys. </p>
<p>The <code>choices</code> key is optional. It is used when there is a list of options.</p>
<p>So the code above collects three (3) inputs (name, phone, and age) and stores them in a variable called <code>answers</code>.</p>
<p>Next, we assign this set of input a unique ID by calling the <code>uuidv4()</code> function and push everything into the <code>info</code> array:</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">const</span> data = {
      <span class="hljs-attr">id</span>: uuidv4(),
      <span class="hljs-attr">name</span>: answers.name,
      <span class="hljs-attr">phone</span>: answers.phone,
      <span class="hljs-attr">age</span>: answers.age,
    };
    info.push(data);
</code></pre>
<p>Finally, we check if the database file exists. We will update the database with the new data if the file has been created or create it and add the new data if it is false.</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">if</span> (fs.existsSync(<span class="hljs-string">"db.json"</span>)) {
      createDetails(info);
    } <span class="hljs-keyword">else</span> {
      fs.appendFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-string">"[]"</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (err) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Could not create db.json"</span>, err);
          <span class="hljs-keyword">return</span>;
        }
        createDetails(info);
      });
    }
</code></pre>
<p>The <code>createDetails</code> function will be used to overwrite the database data. I will create that in a bit.  </p>
<p>In the <code>else</code> (if the file doesn’t exist) block, I created the file using the file system’s <code>appendFile</code> method. This method is used to create a file if it is not there already and add or append data to the bottom of the file. </p>
<p>I am appending <code>[]</code> to the file. So the newly created file will have just <code>[]</code> in it. I called the <code>createDetails</code> function next to add the data collected from the CLI.  </p>
<p>Please type the following code for the createDetails function below the addData function. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createDetails</span>(<span class="hljs-params">info</span>) </span>{
  <span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(info), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-keyword">if</span> (err) {
      <span class="hljs-built_in">console</span>.log(err);
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"saved!"</span>);
  });
}
</code></pre>
<p>This function uses the file system’s <code>writeFile</code> method to overwrite the database with current data. I am using <code>JSON.stringify</code> to convert the <code>info</code> variable to a string because that is the acceptable format when writing to a file. That also explains why I used <code>JSON.parse</code> to convert it to the original type when I retrieved it in the previous section.  </p>
<p><code>writeFile</code> is different from <code>appendFile</code> because <code>writeFile</code> overwrites a file while <code>appendFile</code> adds to the existing content. They are similar in that both methods will create the file if it has not been created.</p>
<p>The last thing to do in this file is invoke or call the function. The way to do that is by typing its name followed by opening and closing braces like this:</p>
<pre><code class="lang-javascript">addData();
</code></pre>
<p>This might work fine, but it wouldn’t do what we want. We need to pass the function as an argument into the <code>queryDB</code> like this:</p>
<pre><code class="lang-javascript">queryDB(addData);
</code></pre>
<p>Now, the <code>addData</code> will be able to communicate with the <code>queryDB</code> function.</p>
<h2 id="heading-how-to-test-the-adddata-file">How to Test the <code>addData</code> File</h2>
<p>Run the command below to test if the <code>addData</code> file works as expected:</p>
<pre><code>node addData
</code></pre><p>It will prompt you for answers. Fill in the answers. After that, your screen should look like mine:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675241012883_Screenshot+2023-02-01+at+09.42.57.png" alt="Image" width="1057" height="236" loading="lazy">
<em>addData output</em></p>
<p>It should also have auto-generated a <code>db.json</code> file with the data you just added.</p>
<p>And that is it for the <code>addData</code> file!</p>
<h2 id="heading-how-to-retrieve-data">How to Retrieve Data</h2>
<p>This section shows how to get the content of the database. All you need to achieve this functionality is the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;

queryDB();
</code></pre>
<p>What the code does is import the <code>queryDB</code> function and invoke it. Paste the code in the <code>retrieveData.js</code> file and execute the file with:</p>
<pre><code>node retrieveData
</code></pre><p>It will return an output similar to this:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675319554801_Screenshot+2023-02-02+at+07.29.43.png" alt="Image" width="1162" height="389" loading="lazy">
<em>retrieveData.js output</em></p>
<p>You might wonder: why did I not call this function in the <code>queryDB</code> file? The reason is that the file performs more than just retrieving data. Calling the <code>queryDB</code> function in its file will alter the result of other files.</p>
<h2 id="heading-how-to-edit-data">How to Edit Data</h2>
<p>This section will now focus on how to update data. The pattern to follow here is:</p>
<ul>
<li>Collect the user’s ID.</li>
<li>Search for the user.</li>
<li>Return the user’s data if the user exists, and set it as the default option.</li>
<li>Ask for updated info. The initial value will be kept if the user presses the <code>Enter</code> key.</li>
<li>Finally, overwrite the database with the updated information.</li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/UmshAmmU-44" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Let’s get to it…  </p>
<p>Navigate into the <code>updateData.js</code> file and paste the following code:</p>
<pre><code><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
<span class="hljs-keyword">import</span> dbFileCheck <span class="hljs-keyword">from</span> <span class="hljs-string">"./dbFileCheck.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateData</span>(<span class="hljs-params">info</span>) </span>{
  dbFileCheck();

  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This is the boilerplate for the <code>updateData</code> function. The new thing here is the <code>dbFileCheck</code> function (made it a while ago) to terminate an operation if the database has not been created.   </p>
<p>The rest of the code will be inside the <code>try…</code> block.</p>
<p>The first thing is to collect the user ID with this code:</p>
<pre><code>    <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"recordID"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Enter Record ID"</span>,
      },
    ]);
</code></pre><p>The second is to search for the user:</p>
<pre><code>    <span class="hljs-keyword">let</span> current;

    info.forEach(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (element.id === answers.recordID) {
        current = element;

        updateDetails(current, info);
      }
    });
</code></pre><p>The code above searches through the users (<code>info</code>) and sets the user found to the <code>current</code> variable. Finally, the <code>updateDetails</code> is called to collect the updated information and overwrite the database with the new data.</p>
<h3 id="heading-how-to-build-the-updatedetails-function">How to build the <code>updateDetails</code> function</h3>
<p>This part will show how to keep track of a user’s initial data while collecting new data. It will update the database with the new data afterward.  </p>
<p>The following code is the boilerplate for the function:</p>
<pre><code><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateDetails</span>(<span class="hljs-params">current, info</span>) </span>{
  <span class="hljs-keyword">try</span> {

  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>This code goes under the <code>updateData</code> operation.  </p>
<p>The code below goes into the <code>try…</code> block. It is for collecting updated information from the user.</p>
<pre><code>  <span class="hljs-keyword">const</span> feedbacks = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">default</span>: current.name,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"name"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your name?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"number"</span>,
        <span class="hljs-attr">default</span>: current.phone,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"phone"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"What's your phone?"</span>,
      },
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"list"</span>,
        <span class="hljs-attr">default</span>: current.age,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"age"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Are an adult?"</span>,
        <span class="hljs-attr">choices</span>: [
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"Y"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Adult"</span> },
          { <span class="hljs-attr">name</span>: <span class="hljs-string">"N"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"Minor"</span> },
        ],
      },
    ]);
</code></pre><p>The <code>default</code> key is new. It holds input that will be used if the user doesn’t provide one. It keeps track of the user’s current data for this code. So the user can hit the <code>Enter</code> button instead of entering the former value again.  </p>
<p>The user’s details should be updated accordingly using this code:</p>
<pre><code>    current.name = feedbacks.name;
    current.phone = feedbacks.phone;
    current.age = feedbacks.age;
</code></pre><p>Finally, overwrite the database with the new value:</p>
<pre><code><span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(info), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
      }
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"updated"</span>);
    });
</code></pre><p>Call the <code>updateData</code> function to bring everything together:</p>
<pre><code>queryDB(updateData)
</code></pre><h3 id="heading-how-to-test-the-updatedata-file">How to test the <code>updateData</code> file</h3>
<p>Run the command below to see how the <code>updateData</code> function performs:</p>
<pre><code>node updateData
</code></pre><p>It will prompt you for an ID. Enter the ID of any record in the database.  </p>
<p>It will then prompt for updated information about the user. Fill in the information and press <code>Enter</code> for any detail that does not need an update. The terminal should look like this at the end:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675324018105_Screenshot+2023-02-02+at+08.45.07.png" alt="Image" width="1334" height="260" loading="lazy">
<em>updateData Output</em></p>
<p>That wraps it up for the <code>updateData</code> file. Records can now be updated.</p>
<h2 id="heading-how-to-delete-data">How to Delete Data</h2>
<p>A CRUD application cannot be completed without the DELETE part. That will be the focus here. It will borrow a bit from the previous sections. So it will not be too much to grasp.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/JptWEtAtOeA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>You'll begin by typing the following code in the <code>removeData.js</code> file:</p>
<pre><code><span class="hljs-keyword">import</span> inquirer <span class="hljs-keyword">from</span> <span class="hljs-string">"inquirer"</span>;
<span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;
<span class="hljs-keyword">import</span> queryDB <span class="hljs-keyword">from</span> <span class="hljs-string">"./queryDB.js"</span>;
<span class="hljs-keyword">import</span> dbFileCheck <span class="hljs-keyword">from</span> <span class="hljs-string">"./dbFileCheck.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeData</span>(<span class="hljs-params">info</span>) </span>{
  dbFileCheck();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> answers = <span class="hljs-keyword">await</span> inquirer.prompt([
      {
        <span class="hljs-attr">type</span>: <span class="hljs-string">"input"</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">"recordID"</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Enter Record ID"</span>,
      },
    ]);

    <span class="hljs-keyword">let</span> remnantData = [];
    info.forEach(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (element.id !== answers.recordID) {
        remnantData.push(element);
      }
    });

    fs.writeFile(<span class="hljs-string">"db.json"</span>, <span class="hljs-built_in">JSON</span>.stringify(remnantData), <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
      }
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Deleted!"</span>);
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Something went wrong!"</span>, error);
  }
}
</code></pre><p>First, the code above collects an ID.  </p>
<p>Next, it uses the ID to search the database data and keeps only data with a different ID in the <code>remnantData</code> array.  </p>
<p>Finally, it overwrites the database with the updated data.  </p>
<p>Call the removeData function at the bottom to put everything together like this:</p>
<pre><code>queryDB(removeData)
</code></pre><p>Now try to test the file using this command:</p>
<pre><code>node removeData
</code></pre><p>The is my output:</p>
<p><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675329363353_Screenshot+2023-02-02+at+10.15.12.png" alt="Image" width="1309" height="109" loading="lazy">
<em>removeData Ouput</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The best way to learn to program is by building. And some of the best projects to build are CRUD applications because they cover the basics of what a professional project requires. That is what I have done in this tutorial.  </p>
<p>I have taught you the basics of Nodejs by building an application that creates, reads, updates, and deletes records. I covered concepts such as reading files, writing to files, loops, conditional statements, modules, and CLI operations.  </p>
<p>All the files for this tutorial are on <a target="_blank" href="https://github.com/EBEREGIT/Nodejs_CLI_app">GitHub</a>.  </p>
<p>You now have all the basics needed to start building applications using Nodejs. Something I will like you to try is to update or delete more than one record at a time.</p>
<p>I have some other tutorials on Nodejs, and I suggest that you follow them in this order to grow your skill:</p>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/build-a-secure-server-with-node-and-express/">How to Build a Secure Server with Node.js and Express and Upload Images with Cloudinary</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-backend-application/">How to Build and Deploy a Backend App with Express, Postgres, Github, and Heroku</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-fullstack-authentication-system-with-react-express-mongodb-heroku-and-netlify/">How to Build a Full-Stack Authentication App With React, Express, MongoDB, Heroku, and Netlify</a></li>
</ul>
<p>Happy Building!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CRUD Operations – Crud Definition in Programming ]]>
                </title>
                <description>
                    <![CDATA[ When interacting with a database or working with an API, you'll often encounter the term CRUD. It is a popular acronym for the four basic operations or functions that a model (in the case of an API) or a database management system uses. This is an ac... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/crud-operations-crud-definition-in-programming/</link>
                <guid isPermaLink="false">66d45f729f2bec37e2da0630</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SQL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Thu, 20 Oct 2022 21:54:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/cover-template--16-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When interacting with a database or working with an API, you'll often encounter the term CRUD. It is a popular acronym for the four basic operations or functions that a model (in the case of an API) or a database management system uses.</p>
<p>This is an acronym everyone learning computer programming will come across, and it's good to get familiar with what it means.</p>
<p>In this article, you will learn what each part of the acronym means, what the CRUD operators do, and how they relate to databases and API.</p>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p>CRUD is an acronym for <strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete. Each of these performs different operations, but they all aim to track and manage data, from a database, API, or whatever.</p>
<p>When creating a database or building APIs, you will want users to be able to manipulate any data available either by fetching these data, updating the data, deleting them, or adding more data. These operations are made possible through CRUD operations.</p>
<p>These operations have functions in Databases, as you can map them to a standard Structured Query Language (SQL) statement. Also, these operations can be mapped to a Hypertext Transfer Protocol (HTTP) method when working with RESTful APIs.</p>
<p>In SQL, the Create operation can be mapped to the INSERT function the same as the POST method in an HTTP request. Here is a table to summarize what each CRUD operation can be mapped to an HTTP request and SQL function:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Letter</td><td>Operation</td><td>HTTP request</td><td>SQL function</td></tr>
</thead>
<tbody>
<tr>
<td>C</td><td>Create</td><td>POST</td><td>INSERT</td></tr>
<tr>
<td>R</td><td>Read</td><td>GET</td><td>SELECT</td></tr>
<tr>
<td>U</td><td>Update</td><td>PATCH/ PUT (if you have <code>id</code> or <code>uuid</code>)</td><td>UPDATE</td></tr>
<tr>
<td>D</td><td>Delete</td><td>DELETE</td><td>DELETE</td></tr>
</tbody>
</table>
</div><p>With some examples, let's now understand how these acronyms work with SQL and HTTP requests.</p>
<h2 id="heading-how-the-create-operation-works">How the Create Operation Works</h2>
<p>Just as its name suggests, you use the create operation to create a new record or entry. This record can be a user's data, a new item, information, or a new row to be added to your database.</p>
<p>For example, let's say you have a database or an array of users which consists of each user's name, age, username, password, and unique ID. You can add a new user to the database or list of users (this is referred to as a new record or entry).</p>
<p>When working with SQL, this is mapped to the INSERT function. A simple UPDATE function will look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> table_name (column1, column2, column3, ...)
  <span class="hljs-keyword">VALUES</span> (value1, value2, value3, ...);
</code></pre>
<p>In the above, you match the new values to their respective column via their name using the <strong>INSERT</strong> function. You can also tweak this, but the emphasis is the INSERT function.</p>
<p>When working with RESTful APIs, you will use the POST HTTP methods. For example, let's use the JavaScript Fetch API:</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'foo'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'bar'</span>,
    <span class="hljs-attr">userId</span>: <span class="hljs-number">1</span>,
  }),
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Content-type'</span>: <span class="hljs-string">'application/json; charset=UTF-8'</span>,
  },
})
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(json));
</code></pre>
<p>In the above example, a new object containing the <code>title</code>, <code>body</code> and <code>userId</code> of the new <code>post</code> is added to the <code>[posts](https://jsonplaceholder.typicode.com/posts)</code> <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">API</a>. The server should return a header with the HTTP response code 201 (CREATED).</p>
<h2 id="heading-how-the-read-operation-works">How the Read Operation Works</h2>
<p>You use the Read operation to read an entire database or search for one or more entries based on certain parameters.</p>
<p>For example, if you have a database of users, you can retrieve the entire list of users or get a particular user...or anything you want. The idea of retrieving can be referred to as READing.</p>
<p>When working with SQL, this is mapped to the SELECT function. A simple SELECT function will look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> menu;
</code></pre>
<p>In the above, you are selecting all the data in the menu table. You can also request specific values via their column names:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> CustomerID, FirstName, LastName, Email, PhoneNumber
    <span class="hljs-keyword">FROM</span>   Customer
</code></pre>
<p>You can also use parameters and lots more, but the emphasis is that you will always use the SELECT function.</p>
<p>When working with RESTful APIs, you will use the GET HTTP method. Although most times, you don't need to specify the method as it is the default method, for example, when using the JavaScript Fetch API:</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>)
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(json));
</code></pre>
<p>When there are no errors, this will return the JSON data from the API, along with a 200 response code representing OK. If there is an error, it will often return a 404 response code (NOT FOUND).</p>
<h2 id="heading-how-the-update-operation-works">How the Update Operation Works</h2>
<p>You use the Update operation to modify existing data. This is just like editing the data. Maybe you want to correct the spelling of a name from Jon Doe to John Doe.</p>
<p>When working with SQL, this is mapped to the UPDATE function. A simple UPDATE function will look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">user</span>
  <span class="hljs-keyword">SET</span> user_name = <span class="hljs-string">'John Doe'</span>, age = <span class="hljs-number">62</span>
  <span class="hljs-keyword">WHERE</span> item_id = <span class="hljs-number">1</span>;
</code></pre>
<p>The request above will change the name and age of the specified user <code>id</code>.</p>
<p>When working with RESTful APIs, you will use either the PUT or PATCH HTTP methods.</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'PUT'</span>,
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">'foo'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'bar'</span>,
    <span class="hljs-attr">userId</span>: <span class="hljs-number">1</span>,
  }),
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Content-type'</span>: <span class="hljs-string">'application/json; charset=UTF-8'</span>,
  },
})
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(json));
</code></pre>
<p>This will return a response with a Status Code of 200 (OK) if the operation is successful.</p>
<h2 id="heading-how-the-delete-operation-works">How the Delete Operation Works</h2>
<p>As you must have guessed, you use this operation to delete a specified entry or record. This is the direct opposite of the Create operation, but for this, you will specify the ID (unique value) you wish to remove.</p>
<p>When working with SQL, this is mapped to the DELETE function. A simple DELETE function will look like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">WHERE</span> user_name=<span class="hljs-string">'John Doe'</span>;
</code></pre>
<p>This will remove the row with the name "John Doe" from the table. If you want to delete all the records from the table, you can use the following:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span>;
</code></pre>
<p>When working with RESTful APIs, then you will make use of the DELETE method:</p>
<pre><code class="lang-js">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts/1'</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span>,
});
</code></pre>
<p>If successful, this should return a response code of 204 (NO CONTENT).</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you have learned what each operation in the CRUD acronym means, what they do, and how they work with SQL and HTTP requests.</p>
<p>In summary, C represents Create and is used to create a new entry. R represents Read and is used to read and retrieve entries. U represents Update and updates an entry. D represents Delete and is used to delete an entry.</p>
<p>You can learn more about <a target="_blank" href="https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/">CRUD operation in JavaScript by building a Todo application in this article</a> written by <a target="_blank" href="https://www.freecodecamp.org/news/author/joy/">Joy Shaheb</a>.</p>
<p>Thanks for reading, and have fun coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CRUD Operations – What is CRUD? ]]>
                </title>
                <description>
                    <![CDATA[ Despite being commonly pronounced /krʌd/, CRUD is not a word. It’s an abbreviation that stands for Create, Read, Update, and Delete or Destroy. In this article, I will show you what CRUD means, and what the individual terms mean and do. I will also s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/crud-operations-explained/</link>
                <guid isPermaLink="false">66adf093f452caf50fb1fddb</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 15 Jun 2022 16:51:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/06/crud.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Despite being commonly pronounced <code>/krʌd/</code>, CRUD is not a word. It’s an abbreviation that stands for Create, Read, Update, and Delete or Destroy.</p>
<p>In this article, I will show you what CRUD means, and what the individual terms mean and do. I will also show you how create, read, update, and delete operations work in the real world.</p>
<h2 id="heading-what-well-cover">What We'll Cover</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-crud">What is CRUD?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-create-operation-and-how-does-it-work">What is the <code>CREATE</code> Operation and How Does it Work? </a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-read-operation-and-how-does-it-work">What is the <code>READ</code> Operation and How Does it Work?</a></li>
<li><a class="post-section-overview" href="#whatisupdateoperationandhowdoesitwork">What is the <code>UPDATE</code> Operation and How Does it Work?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-delete-operation-and-how-does-it-work">What is the <code>DELETE</code> Operation and How Does it Work?</a> </li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p>CRUD refers to the four basic operations a software application should be able to perform – Create, Read, Update, and Delete. </p>
<p>In such apps, users must be able to <strong>create data</strong>, have access to the data in the UI by <strong>reading</strong> the data, <strong>update</strong> or <strong>edit</strong> the data, and <strong>delete</strong> the data. </p>
<p>In full-fledged applications, CRUD apps consist of 3 parts: an API (or server), a database, and a user interface (UI). </p>
<p>The API contains the code and methods, the database stores and helps the user retrieve the information, while the user interface helps users interact with the app.</p>
<p>You can make a CRUD app with any of the programming languages out there. And the app doesn’t have to be full stack – you can make a CRUD app with client-side JavaScript. </p>
<p>In fact, the app with which I will be showing you how create, read, update and delete operations work is made with client-side JavaScript. </p>
<p>Each letter in the CRUD acronym has a corresponding HTTP request method. 
| <strong>CRUD Operation</strong>| <strong>HTTP Request Method</strong>| 
| ----------- | ----------- |
| Create| POST |
| Read | GET|
| Update| PUT or PATCH|
| Delete | DELETE|</p>
<h2 id="heading-what-is-the-create-operation-and-how-does-it-work">What is the <code>CREATE</code> Operation and How Does it Work?</h2>
<p>In CRUD, the create operation does what the name implies. It means creating an entry. This entry could be an account, user information, a post, or a task.</p>
<p>As I pointed out earlier, the HTTP protocol that implements a <code>CREATE</code> operation is the POST method.</p>
<p>In a SQL database, to create is to <code>INSERT</code>. In a NoSQL database like MongoDB, you create with the <code>insert()</code> method.</p>
<p>In a user interface, this GIF below shows how the <code>CREATE</code> operation works:
<img src="https://www.freecodecamp.org/news/content/images/2022/06/create-op.gif" alt="create-op" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-the-read-operation-and-how-does-it-work">What is the <code>READ</code> Operation and How Does it Work?</h2>
<p>The <code>READ</code> operation means getting access to the inputs or entries in the UI. That is, seeing it. Again, the entry could be anything from user information to social media posts, and others.</p>
<p>This access could mean the user getting access to the created entries right after creating them, or searching for them. Searching is implemented to allow the user to filter out the entries they don’t need.</p>
<p>The HTTP protocol that implements a <code>READ</code> operation is the GET method.</p>
<p>In a SQL database, to read is to <code>SELECT</code> an entry. In a NoSQL database like MongoDB, you read with the <code>find()</code> or <code>findById()</code> method.
<img src="https://www.freecodecamp.org/news/content/images/2022/06/read-operation.png" alt="read-operation" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-the-update-operation-and-how-does-it-work">What is the <code>UPDATE</code> Operation and How Does it Work?</h2>
<p><code>UPDATE</code> is the operation that allows you to modify existing data. That is, editing the data.</p>
<p>Unlike <code>READ</code>, the <code>UPDATE</code> operation alters the existing data by making changes to it. </p>
<p>PUT and PATCH are the HTTP protocols with which you can implement an <code>UPDATE</code> operation, depending on what you need.</p>
<p><code>PUT</code> should be used when you want the entire entry updated, and PATCH if you don’t want the entire entry to be modified.</p>
<p>In a SQL database, you use <code>UPDATE</code> to update an entry. In a NoSQL database like MongoDB, you can implement an update feature with the <code>findByIdAndUpdate()</code> method.</p>
<p>In a user interface, this GIF below shows how the <code>UPDATE</code> operation works:
<img src="https://www.freecodecamp.org/news/content/images/2022/06/update-op.gif" alt="update-op" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-the-delete-operation-and-how-does-it-work">What is the <code>DELETE</code> Operation and How Does it Work?</h2>
<p>To delete is to get rid of an entry from the UI and the database. </p>
<p><code>DELETE</code> is the HTTP protocol for implementing a <code>DELETE</code> operation.</p>
<p>In a SQL database, <code>DELETE</code> is used to delete an entry. In a NoSQL database like MongoDB, you can implement delete with the <code>findByIdAndDelete()</code> method.
<img src="https://www.freecodecamp.org/news/content/images/2022/06/delete-op.gif" alt="delete-op" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article showed you what CRUD means and what each individual operation in a CRUD app does.</p>
<p>You can think about CRUD in this way:</p>
<ul>
<li>You create a social account and fill in your information - <code>CREATE</code></li>
<li>You get access to the information you entered and people can search for you – <code>READ</code></li>
<li>You get a new job at Google and changed your employment status to employed – <code>UPDATE</code>  </li>
<li>You get tired of social media toxicity and delete your account - <code>DELETE</code></li>
</ul>
<p>To learn how you can make your own CRUD app, check out <a target="_blank" href="https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/">this tutorial</a> by Joy Shaheb of freeCodeCamp.</p>
<p>Keep coding 👋</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Axios React – How to Make Get, Post, and Delete API Requests ]]>
                </title>
                <description>
                    <![CDATA[ Axios is an HTTP client library based on promises. It makes sending asynchronous HTTP requests to REST endpoints easier and helps you perform CRUD operations. This REST endpoint/API could be an external API like the Google API, GitHub API, and so on ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/axios-react-how-to-make-get-post-and-delete-api-requests/</link>
                <guid isPermaLink="false">66d45f638812486a37369cd7</guid>
                
                    <category>
                        <![CDATA[ axios ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Tue, 17 May 2022 16:12:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/cover-template.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><a target="_blank" href="https://axios-http.com/">Axios</a> is an HTTP client library based on promises. It makes sending asynchronous HTTP requests to REST endpoints easier and helps you perform CRUD operations.</p>
<p>This REST endpoint/API could be an external API like the Google API, GitHub API, and so on – or it could be your own backend Node.js server.</p>
<p>In this guide, we will learn how to make Axios GET, POST, and DELETE API requests in React. This simply refers to how we retrieve data from an API, add data to the API, and then delete data from our API.</p>
<p>Get, Post, and Delete API requests are among the most common daily requests made by developers. After all, we will always need to fetch data to display on our application or perform certain operations, as well as add and delete data to/from our API.</p>
<h3 id="heading-heres-an-interactive-scrim-about-how-to-make-axios-get-post-and-delete-api-requests-in-react">Here's an interactive scrim about how to make Axios GET, POST, and DELETE API requests in React:</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/co6e84267986fe1194cb9ac07?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-why-axios">Why Axios?</h2>
<p>The next question you might have is why we are using Axios, given that we will need to install an additional library. Here are some reasons:</p>
<ul>
<li><p>Axios uses <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a> under the hood, and it is widely supported by most browsers, including older ones like Internet Explorer 11. Fetch(), on the other hand, is only compatible with Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.3+ (you can see the full compatibly table on <a target="_blank" href="https://caniuse.com/fetch">CanIUse.com</a>).</p>
</li>
<li><p>When sending requests, Axios automatically signifies the data, unlike fetch(), which requires us to do it manually.</p>
</li>
<li><p>Unlike the Fetch API, which requires you to check the status code and throw the error yourself, Axios has better error handling and can throw 400 and 500 range errors.</p>
</li>
</ul>
<h2 id="heading-how-to-get-started-with-axios-in-react">How to Get Started with Axios in React</h2>
<p>To get started with Axios in your React application, first install React into your project with the following command:</p>
<pre><code class="lang-bash">npm install axios
</code></pre>
<p>Once that is completed, we will be using the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts">JSONPlacholder Posts API</a> to learn how to fetch these posts into our React application, add new posts, and finally delete a specific post with Axios.</p>
<p>Because this is a React application, we will use React hooks to gain access to states and other features. The hooks we'll be using are <code>useEffect()</code> and <code>useState()</code>.</p>
<p>Essentially, we'll use the <code>useEffect()</code> hook to fetch posts as soon as the app renders/mounts, while the <code>useState()</code> hook will help us create a local storage for our data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/image-89.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-the-axios-instance">How to Create the Axios Instance</h3>
<p>Once you've successfully installed Axios, it's a good idea to create an Axios instance. It's not required, but it saves us time.</p>
<p>To create an instance, we'll use the <code>.create()</code> method, which lets us specify information such as the URL and possibly headers:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> client = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://jsonplaceholder.typicode.com/posts"</span> 
});
</code></pre>
<h2 id="heading-how-to-make-a-get-request-with-axios-in-react">How to Make a GET Request with Axios in React</h2>
<p>You can use GET requests to get data from an endpoint, and it'll happen as soon as the app renders thanks to the <code>useEffect()</code> hook.</p>
<p>We'll use the variable and then attach the <code>.get()</code> method to make a GET request to our endpoint/API. Then we'll use a <code>.then()</code> callback to get back all the response data, because we already have an Axios instance that holds the <code>baseURL</code> assigned to a variable (client).</p>
<p>Using the <code>.data</code> property, we obtain the response data, which is the actual data from the response object.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   useEffect(<span class="hljs-function">() =&gt;</span> {
      client.get(<span class="hljs-string">'?_limit=10'</span>).then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
         setPosts(response.data);
      });
   }, []);

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>We set the data to the state we created, so it can be consumed within our application.</p>
<h3 id="heading-how-to-consume-a-get-request">How to Consume a GET Request</h3>
<p>After successfully implementing the GET request, the next step is to consume the data stored in the <code>posts</code> state.</p>
<p>Because we are querying for an array of ten posts, we will have to loop through this state to get these ten posts into our application:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>All Posts 📫<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    {posts.map((post) =&gt; {
       return (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-card"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-title"</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"post-body"</span>&gt;</span>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
             <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"delete-btn"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
             <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       );
    })}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);

<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="heading-how-to-make-a-post-request-with-axios-in-react">How to Make a POST Request with Axios in React</h2>
<p>You use a POST request to send data to an endpoint. It works similarly to a GET request, except that the function created to perform this task will be triggered when the form is submitted or otherwise.</p>
<p>This takes an object to send the data in and also adds the data to the state by spreading the previous data and then adding the new data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-function">(<span class="hljs-params">title, body</span>) =&gt;</span> {
      client
         .post(<span class="hljs-string">''</span>, {
            <span class="hljs-attr">title</span>: title,
            <span class="hljs-attr">body</span>: body,
         })
         .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
            setPosts([response.data, ...posts]);
         });
      setTitle(<span class="hljs-string">''</span>);
      setBody(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>When the form is submitted, we call the <code>handleSubmit()</code> function, which prevents the page from reloading. It also calls the main function <code>addPosts()</code> by passing the data entered into the form as a parameter.</p>
<h3 id="heading-how-to-perform-a-delete-request-in-react">How to Perform a DELETE Request in React</h3>
<p>As the name implies, you use this to delete specific data from your endpoint/API as well as your UI – DELETE can handle both.</p>
<p>For this, we will use the DELETE method in conjunction with the client variable where we initialized Axios. This is how the request will look:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

   <span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
      client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Basically, there is a <code>onClick"=() =&gt;"deletePost"("post."id)</code> method on the delete button that triggers the <code>deletePost()</code> method. We passed it the <code>ID</code> of the particular post we are attempting to delete so we can identify the post.</p>
<p>We delete it from the UI after we delete it from the endpoint/API by using the filter method to return an array that does not contain that element.</p>
<h2 id="heading-how-to-make-requests-in-react-with-asyncawait">How to Make Requests in React with Async/Await</h2>
<p>So far, we've seen how to make Axios requests with the promise syntax. Now, let's see how we can use async/await to write less code and avoid the <code>.then</code> chaining, which is much more difficult to understand.</p>
<p>To use async/await, first call <code>async</code> in the function. Then add the <code>await</code> syntax in front of the function when making a request and expecting a response to wait until the promise settles with the result.</p>
<p>When we use async/await, all of our Axios requests will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
   <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [body, setBody] = useState(<span class="hljs-string">''</span>);
   <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

    <span class="hljs-comment">// GET with Axios</span>
   useEffect(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
         <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
         setPosts(response.data);
      };
      fetchPost();
   }, []);

   <span class="hljs-comment">// DELETE with Axios</span>
   <span class="hljs-keyword">const</span> deletePost = <span class="hljs-keyword">async</span> (id) =&gt; {
      <span class="hljs-keyword">await</span> client.delete(<span class="hljs-string">`<span class="hljs-subst">${id}</span>`</span>);
      setPosts(
         posts.filter(<span class="hljs-function">(<span class="hljs-params">post</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> post.id !== id;
         })
      );
   };

   <span class="hljs-comment">// handle form submission</span>
   <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      addPosts(title, body);
   };

   <span class="hljs-comment">// POST with Axios</span>
   <span class="hljs-keyword">const</span> addPosts = <span class="hljs-keyword">async</span> (title, body) =&gt; {
      <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">''</span>, {
         <span class="hljs-attr">title</span>: title,
         <span class="hljs-attr">body</span>: body,
      });
      setPosts([response.data, ...posts]);
      setTitle(<span class="hljs-string">''</span>);
      setBody(<span class="hljs-string">''</span>);
   };

   <span class="hljs-keyword">return</span> (
      <span class="hljs-comment">// ...</span>
   );
};
</code></pre>
<h2 id="heading-how-to-handle-errors-in-axios">How to Handle Errors in Axios</h2>
<p>When consuming data from an API, it is always recommended that we handle errors to help show the type of error we get. These errors may occur as a result of us passing incorrect data, making a request to the incorrect API, or experiencing a network error.</p>
<p>We can handle errors in Axios by using the <code>.then()</code> and <code>.catch()</code> methods, or by using the <code>try...catch</code> block for async/await Axios requests.</p>
<h3 id="heading-how-to-handle-errors-in-axios-with-the-catch-method">How to Handle Errors in Axios with the <code>.catch</code> Method</h3>
<p>You can implement this by attaching a <code>.catch()</code> method to the <code>.then()</code> method to handle errors. Suppose the <code>.then()</code> method fails:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  client
     .get(<span class="hljs-string">'?_limit=10'</span>)
     .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
        setPosts(response.data);
     })
     .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(error);
     });
}, []);
</code></pre>
<h3 id="heading-how-to-handle-errors-in-axios-with-the-trycatch-block">How to Handle Errors in Axios with the try…catch Block</h3>
<p>For the async/await scenario, the <code>try...catch</code> block will look like this:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> () =&gt; {
     <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'?_limit=10'</span>);
        setPosts(response.data);
     } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
     }
  };
  fetchPost();
}, []);
</code></pre>
<p>You can read more about handling errors with Axios <a target="_blank" href="https://stackabuse.com/handling-errors-with-axios/">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to use Axios, one of the most powerful HTTP client libraries, to perform the three basic API requests.</p>
<p>You can see the full implementation of how I built the <a target="_blank" href="https://github.com/olawanlejoel/posts-jsonplaceholder-demo">post's application using React and Axios in this repository</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn CRUD Operations in JavaScript by Building TODO APP ]]>
                </title>
                <description>
                    <![CDATA[ Today we're gonna learn how to do CRUD Operations in JavaScript by making a Todo App. Let's get started 🔥 This is the app we're making today: Live preview GitHub Repository You can watch this tutorial on YouTube as well if you like 🎥 https://you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/</link>
                <guid isPermaLink="false">66b2095df31aa965000e588c</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joy Shaheb ]]>
                </dc:creator>
                <pubDate>Wed, 13 Apr 2022 17:57:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/Frame-12--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Today we're gonna learn how to do CRUD Operations in JavaScript by making a Todo App. Let's get started 🔥</p>
<p>This is the app we're making today:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ut6o5hbsrzb5eccm72v.png" alt="App that we're making today" width="611" height="848" loading="lazy"></p>
<ul>
<li><a target="_blank" href="https://crud-application-al9am9v2v-joyshaheb.vercel.app/">Live preview</a></li>
<li><a target="_blank" href="https://github.com/JoyShaheb/CRUD-Application">GitHub Repository</a></li>
</ul>
<h2 id="heading-you-can-watch-this-tutorial-on-youtube-as-well-if-you-like">You can watch this tutorial on YouTube as well if you like 🎥</h2>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fL9cts8ykbU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li>What is CRUD?</li>
<li>Understanding CRUD Principles</li>
<li>How to Make a To-Do App using CRUD Operations</li>
</ul>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agloiqjwk11qr7mu39y4.png" alt="Image description" width="1280" height="613" loading="lazy"></p>
<p>CRUD stands for -</p>
<ul>
<li>C: Create</li>
<li>R: Read</li>
<li>U: Update</li>
<li>D: Delete</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3md2xtw76u0y1fr8polm.png" alt="CRUD Fullform" width="1280" height="720" loading="lazy"></p>
<p>CRUD is a type of mechanism that allows you to create data, read data, edit it, and delete those data. In our case, we're gonna make a Todo app, so we will have 4 options to create tasks, read tasks, update tasks, or delete tasks.</p>
<h2 id="heading-understanding-crud-principles">Understanding CRUD Principles</h2>
<p>Before starting the tutorial, first, let's understand the CRUD principles. For that, let's create a very very simple Social Media Application.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cr1ueopcx4bfgz7j8ov.gif" alt="Social Media App Project" width="1036" height="720" loading="lazy"></p>
<h2 id="heading-setup">Setup</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9o3h86jd7md2bo54n4cd.png" alt="Project Setup" width="1280" height="613" loading="lazy"></p>
<p>For this project, we will be following these steps below:</p>
<ul>
<li>Create 3 files named index.html, style.css, and main.js</li>
<li>Link the JavaScript and CSS file to index.html</li>
<li>Start your live server</li>
</ul>
<h3 id="heading-html">HTML</h3>
<p>Inside the body tag, create a div with a class name <code>.container</code>. There, we will have 2 sections, <code>.left</code> and <code>.right</code> 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Social Media App<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

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

  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>On the left side, we will create our posts. On the right side, we can see, update, and delete our posts. Now, create a form inside the .left div tag 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"left"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"form"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"post"</span>&gt;</span> Write your post here<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"msg"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Post<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Write this code inside the HTML so that we can display our post on the right side 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"right"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Your posts here<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"posts"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Next, we'll insert the font-awesome CDN inside the head tag to use its fonts in our project 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"</span> /&gt;</span>
</code></pre>
<p>Now, we're gonna make some sample posts with delete and edit icons. Write this code inside the div with the id #posts: 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"posts"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello world post 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"options"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-edit"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash-alt"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello world post 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"options"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-edit"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash-alt"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The result so far looks like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ra3w4flp2et2wsf94m2.png" alt="HTML Markup result" width="465" height="681" loading="lazy"></p>
<h3 id="heading-css">CSS</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/djlwav0yj8w5vld3ux5z.png" alt="Adding CSS for project 1" width="1280" height="613" loading="lazy"></p>
<p>Let's keep it simple. Write these styles inside your stylesheet: 👇</p>
<pre><code class="lang-CSS"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: sans-serif;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">50px</span>;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">50px</span>;
}

<span class="hljs-selector-id">#posts</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
}

<span class="hljs-selector-tag">i</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Now, write these styles for the post div and option icons: 👇</p>
<pre><code class="lang-CSS"><span class="hljs-selector-id">#posts</span> <span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.options</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">25px</span>;
}

<span class="hljs-selector-id">#msg</span> {
  <span class="hljs-attribute">color</span>: red;
}
</code></pre>
<p>The results so far look like this:👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dttu77ecfpd235byt4pi.png" alt="The result after adding the css part project 1" width="730" height="435" loading="lazy"></p>
<h3 id="heading-javascript-part">JavaScript Part</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nl1o5q5kcymkfyrsme8f.png" alt="Starting the javascript part" width="1280" height="613" loading="lazy"></p>
<p>According to this flow chart, we will go forward with the project. Don't worry, I'll explain everything along the way. 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vlsw0253j7st1ictip03.png" alt="flow chart" width="847" height="908" loading="lazy"></p>
<h4 id="heading-form-validation">Form Validation</h4>
<p>First, let's target all the ID selectors from the HTML in JavaScript. Like this: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"form"</span>);
<span class="hljs-keyword">let</span> input = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"input"</span>);
<span class="hljs-keyword">let</span> msg = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"msg"</span>);
<span class="hljs-keyword">let</span> posts = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"posts"</span>);
</code></pre>
<p>Then, build a submit event listener for the form so that it can prevent the default behaviour of our App. At the same time, we will create a function named <code>formValidation</code>. 👇</p>
<pre><code class="lang-js">form.addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.preventDefault();
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"button clicked"</span>);

  formValidation();
});

<span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {};
</code></pre>
<p>Now, we're gonna make an if else statement inside our <code>formValidation</code> function. This will help us prevent users from submitting blank input fields. 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (input.value === <span class="hljs-string">""</span>) {
    msg.innerHTML = <span class="hljs-string">"Post cannot be blank"</span>;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"failure"</span>);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"successs"</span>);
    msg.innerHTML = <span class="hljs-string">""</span>;
  }
};
</code></pre>
<p>Here's the result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7sb8faq21j5dzy9vlswj.gif" alt="7sb8faq21j5dzy9vlswj" width="1036" height="720" loading="lazy"></p>
<p>As you can see, a message will also show up if the user tries to submit the form blank.</p>
<h4 id="heading-how-to-accept-data-from-input-fields">How to accept data from input fields</h4>
<p>Whatever data we get from the input fields, we will store them in an object. Let's create an object named <code>data</code>. And, create a function named <code>acceptData</code>: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> data = {};

<span class="hljs-keyword">let</span> acceptData = <span class="hljs-function">() =&gt;</span> {};
</code></pre>
<p>The main idea is that, using the function, we collect data from the inputs and store them in our object named <code>data</code>. Now let's finish building our <code>acceptData</code> function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> acceptData = <span class="hljs-function">() =&gt;</span> {
  data[<span class="hljs-string">"text"</span>] = input.value;
  <span class="hljs-built_in">console</span>.log(data);
};
</code></pre>
<p>Also, we need the <code>acceptData</code> function to work when the user clicks the submit button. For that, we will fire this function in the else statement of our <code>formValidation</code> function. 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (input.value === <span class="hljs-string">""</span>) {
    <span class="hljs-comment">// Other codes are here</span>
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Other codes are here</span>
    acceptData();
  }
};
</code></pre>
<p>When we input data and submit the form, on the console we can see an object holding our user's input values. Like this: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jje41w8b70hpdgyonpqj.png" alt="result so far on the console" width="1134" height="262" loading="lazy"></p>
<h4 id="heading-how-to-create-posts-using-javascript-template-literals">How to create posts using JavaScript template literals</h4>
<p>In order to post our input data on the right side, we need to create a div element and append it to the posts div. First, let's create a function and write these lines: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> createPost = <span class="hljs-function">() =&gt;</span> {
  posts.innerHTML += <span class="hljs-string">``</span>;
};
</code></pre>
<p>The backticks are template literals. It will work as a template for us. Here, we need 3 things: a parent div, the input itself, and the options div which carries the edit and delete icons. Let's finish our function 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> createPost = <span class="hljs-function">() =&gt;</span> {
  posts.innerHTML += <span class="hljs-string">`
  &lt;div&gt;
    &lt;p&gt;<span class="hljs-subst">${data.text}</span>&lt;/p&gt;
    &lt;span class="options"&gt;
      &lt;i onClick="editPost(this)" class="fas fa-edit"&gt;&lt;/i&gt;
      &lt;i onClick="deletePost(this)" class="fas fa-trash-alt"&gt;&lt;/i&gt;
    &lt;/span&gt;
  &lt;/div&gt;
  `</span>;
  input.value = <span class="hljs-string">""</span>;
};
</code></pre>
<p>In our <code>acceptdata</code> function, we will fire our <code>createPost</code> function. Like this: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> acceptData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Other codes are here</span>

  createPost();
};
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cr1ueopcx4bfgz7j8ov.gif" alt="Result so far" width="1036" height="720" loading="lazy"></p>
<p>So far so good guys, we're almost done with project 1.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyrijoc70cy0sebiu1a5.png" alt="so far so good " width="1280" height="613" loading="lazy"></p>
<h4 id="heading-how-to-delete-a-post">How to delete a post</h4>
<p>In order to delete a post, first of all, let's create a function inside our javascript file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> deletePost = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {};
</code></pre>
<p>Next up, we fire this <code>deletePost</code> function inside all of our delete icons using an onClick attribute. You'll write these lines in HTML and on the template literal. 👇</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">"deletePost(this)"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-trash-alt"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
</code></pre>
<p>The <code>this</code> keyword will refer to the element that fired the event. in our case, the <code>this</code> refers to the delete button.</p>
<p>Look carefully, the parent of the delete button is the span with class name options. The parent of the span is the div. So, we write <code>parentElement</code> twice so that we can jump from the delete icon to the div and target it directly to remove it. </p>
<p>Let's finish our function. 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> deletePost = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.parentElement.parentElement.remove();
};
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9upccmzs4zszg1nfrdf.gif" alt="deleting a post result" width="1120" height="420" loading="lazy"></p>
<h4 id="heading-how-to-edit-a-post">How to edit a post</h4>
<p>In order to edit a post, first of all, let's create a function inside our JavaScript file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> editPost = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {};
</code></pre>
<p>Next up, we fire this <code>editPost</code> function inside all of our edit icons using an onClick attribute. You'll write these lines in HTML and on the template literal. 👇</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">"editPost(this)"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-edit"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
</code></pre>
<p>The <code>this</code> keyword will refer to the element that fired the event. In our case, the <code>this</code> refers to the edit button.</p>
<p>Look carefully, the parent of the edit button is the span with class name options. The parent of the span is the div. So, we write <code>parentElement</code> twice so that we can jump from the edit icon to the div and target it directly to remove it.</p>
<p>Then, whatever data is inside the post, we bring it back on the input field to edit it.</p>
<p>Let's finish our function. 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> editPost = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  input.value = e.parentElement.previousElementSibling.innerHTML;
  e.parentElement.parentElement.remove();
};
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqymvra7ejzi59ekpscd.gif" alt="Editing a post result" width="1120" height="420" loading="lazy"></p>
<h2 id="heading-take-a-break">Take a Break!</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rywq5vr0yz4e0hoosfn9.png" alt="Take a Break" width="1280" height="613" loading="lazy"></p>
<p>Congratulations everyone for completing project 1. Now, take a small break!</p>
<h1 id="heading-how-to-make-a-to-do-app-using-crud-operations">How to Make a To-Do App using CRUD Operations</h1>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbjnnnfvbqmmm8x3mdfw.png" alt="Let's make a todo app" width="1280" height="613" loading="lazy"></p>
<p>Let's start making project 2, which is a To-Do App.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pg9yjnp9s7176xomxlnj.png" alt="Project setup" width="1280" height="546" loading="lazy"></p>
<p>For this project, we will be following these steps below:</p>
<ul>
<li>Create 3 files named index.html, style.css, and main.js</li>
<li>Link the JavaScript and CSS files to index.html</li>
<li>Start our live server</li>
</ul>
<h3 id="heading-html-1">HTML</h3>
<p>Write this starter code inside the HTML file: 👇</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-3"</span>&gt;</span>TODO App<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"addNew"</span> <span class="hljs-attr">data-bs-toggle</span>=<span class="hljs-string">"modal"</span> <span class="hljs-attr">data-bs-target</span>=<span class="hljs-string">"#form"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Add New Task<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fas fa-plus"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The div with an id <code>addNew</code> is the button that will open the modal. The span will be displayed on the button. The <code>i</code> is the icon from font-awesome.</p>
<p>We're going to use bootstrap to make our modal. We'll use the modal to add new tasks. For that, add the bootstrap CDN link inside the head tag. 👇</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"</span>
  <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
/&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>
  <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"</span>
  <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"</span>
  <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>To see the created tasks, we'll use a div with an id tasks, inside the div with the classname app. 👇</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center my-3"</span>&gt;</span>Tasks<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tasks"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Insert the font-awesome CDN inside the head tag to use fonts in our project 👇</p>
<pre><code class="lang-HTML"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"</span> /&gt;</span>
</code></pre>
<p>Copy and paste the code below which are from the bootstrap modal. It carries a form with 3 input fields and a submit button. If you want then you can search Bootstrap's website by writing 'modal' in the search bar.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Modal --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">form</span>
  <span class="hljs-attr">class</span>=<span class="hljs-string">"modal fade"</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">"form"</span>
  <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>
  <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"exampleModalLabel"</span>
  <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-dialog"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-content"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-title"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"exampleModalLabel"</span>&gt;</span>Add New Task<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"btn-close"</span>
          <span class="hljs-attr">data-bs-dismiss</span>=<span class="hljs-string">"modal"</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Task Title<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">""</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"textInput"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"msg"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Due Date<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">""</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dateInput"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Description<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">""</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"textarea"</span>
          <span class="hljs-attr">cols</span>=<span class="hljs-string">"30"</span>
          <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-secondary"</span> <span class="hljs-attr">data-bs-dismiss</span>=<span class="hljs-string">"modal"</span>&gt;</span>
          Close
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"add"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Add<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eazu2i62bilebhgbrclr.png" alt="Html file setup" width="1058" height="190" loading="lazy"></p>
<p>We're done with the HTML file setup. Let's start the CSS.</p>
<h3 id="heading-css-1">CSS</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqldzsv7vcq7ed4sbptj.png" alt="Adding the css part" width="1280" height="613" loading="lazy"></p>
<p>Add these styles in the body so that we can keep our app at the exact center of the screen.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: sans-serif;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#e5e5e5</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}
</code></pre>
<p>Let's style the div with the classname app. 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.app</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">5px</span> solid <span class="hljs-number">#abcea1</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
}
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vuunx9tkgvw5uxqq05ab.png" alt="App styles" width="502" height="724" loading="lazy"></p>
<p>Now, let's style the button with the id <code>addNew</code>. 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#addNew</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">171</span>, <span class="hljs-number">206</span>, <span class="hljs-number">161</span>, <span class="hljs-number">0.35</span>);
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.fa-plus</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#abcea1</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">3px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">3px</span>;
}
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mt353dpjsczqtf8msb71.png" alt="Add new task Button" width="455" height="715" loading="lazy"></p>
<p>If you click on the button, the modal pops up like this: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfmc7fyzdef7nnmxf7ap.gif" alt="Modal poping" width="792" height="780" loading="lazy"></p>
<h3 id="heading-add-the-js">Add the JS</h3>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv4u6j0gafmqxwoh6rpm.png" alt="Adding the JavaScript" width="1280" height="555" loading="lazy"></p>
<p>In the JavaScript file, first of all, select all the selectors from the HTML that we need to use. 👇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"form"</span>);
<span class="hljs-keyword">let</span> textInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"textInput"</span>);
<span class="hljs-keyword">let</span> dateInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"dateInput"</span>);
<span class="hljs-keyword">let</span> textarea = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"textarea"</span>);
<span class="hljs-keyword">let</span> msg = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"msg"</span>);
<span class="hljs-keyword">let</span> tasks = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"tasks"</span>);
<span class="hljs-keyword">let</span> add = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"add"</span>);
</code></pre>
<h4 id="heading-form-validations">Form Validations</h4>
<p>We cannot let a user submit blank input fields. So, we need to validate the input fields. 👇</p>
<pre><code class="lang-javascript">form.addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.preventDefault();
  formValidation();
});

<span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (textInput.value === <span class="hljs-string">""</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"failure"</span>);
    msg.innerHTML = <span class="hljs-string">"Task cannot be blank"</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"success"</span>);
    msg.innerHTML = <span class="hljs-string">""</span>;
  }
};
</code></pre>
<p>Also, add this line inside the CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#msg</span> {
  <span class="hljs-attribute">color</span>: red;
}
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j0b0aidh5hbc2hxkp378.gif" alt="Image description" width="792" height="780" loading="lazy"></p>
<p>As you can see, the validation is working. The JavaScript code doesn't let the user submit blank input fields, otherwise you're gonna see an error message.</p>
<h4 id="heading-how-to-collect-data-and-use-local-storage">How to collect data and use local storage</h4>
<p>Whatever inputs the user writes, we need to collect them and store them in local storage. </p>
<p>First, we collect the data from the input fields, using the function named <code>acceptData</code> and an array named <code>data</code>. Then we push them inside the local storage like this: 👇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> data = [];

<span class="hljs-keyword">let</span> acceptData = <span class="hljs-function">() =&gt;</span> {
  data.push({
    <span class="hljs-attr">text</span>: textInput.value,
    <span class="hljs-attr">date</span>: dateInput.value,
    <span class="hljs-attr">description</span>: textarea.value,
  });

  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"data"</span>, <span class="hljs-built_in">JSON</span>.stringify(data));

  <span class="hljs-built_in">console</span>.log(data);
};
</code></pre>
<p>Also note that this will never work unless you invoke the function <code>acceptData</code> inside the else statement of the form validation. Follow along here: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-comment">// Other codes are here</span>
   <span class="hljs-keyword">else</span> {

    <span class="hljs-comment">// Other codes are here</span>

    acceptData();
  }
};
</code></pre>
<p>You may have noticed that the modal doesn't close automatically. To solve this, write this small function inside the else statement of the form validation: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> formValidation = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-comment">// Other codes are here</span>
   <span class="hljs-keyword">else</span> {

    <span class="hljs-comment">// Other codes are here</span>

    acceptData();
    add.setAttribute(<span class="hljs-string">"data-bs-dismiss"</span>, <span class="hljs-string">"modal"</span>);
    add.click();

    (<span class="hljs-function">() =&gt;</span> {
      add.setAttribute(<span class="hljs-string">"data-bs-dismiss"</span>, <span class="hljs-string">""</span>);
    })();
  }
};
</code></pre>
<p>If you open Chrome dev tools, go to the application and open the local storage. You can see this result: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mku6j28tknry3xqrwg3.png" alt="Local Storage Result" width="1198" height="432" loading="lazy"></p>
<h4 id="heading-how-to-create-new-tasks">How to create new tasks</h4>
<p>In order to create a new task, we need to create a function, use template literals to create the HTML elements, and use a map to push the data collected from the user inside the template. Follow along here: 👇</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> createTasks = <span class="hljs-function">() =&gt;</span> {
  tasks.innerHTML = <span class="hljs-string">""</span>;
  data.map(<span class="hljs-function">(<span class="hljs-params">x, y</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (tasks.innerHTML += <span class="hljs-string">`
    &lt;div id=<span class="hljs-subst">${y}</span>&gt;
          &lt;span class="fw-bold"&gt;<span class="hljs-subst">${x.text}</span>&lt;/span&gt;
          &lt;span class="small text-secondary"&gt;<span class="hljs-subst">${x.date}</span>&lt;/span&gt;
          &lt;p&gt;<span class="hljs-subst">${x.description}</span>&lt;/p&gt;

          &lt;span class="options"&gt;
            &lt;i onClick= "editTask(this)" data-bs-toggle="modal" data-bs-target="#form" class="fas fa-edit"&gt;&lt;/i&gt;
            &lt;i onClick ="deleteTask(this);createTasks()" class="fas fa-trash-alt"&gt;&lt;/i&gt;
          &lt;/span&gt;
        &lt;/div&gt;
    `</span>);
  });

  resetForm();
};
</code></pre>
<p>Also note that the function will never run unless you invoke it inside the <code>acceptData</code> function, like this: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> acceptData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Other codes are here</span>

  createTasks();
};
</code></pre>
<p>Once we're done collecting and accepting data from the user, we need to clear the input fields. For that we create a function called <code>resetForm</code>. Follow along: 👇</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> resetForm = <span class="hljs-function">() =&gt;</span> {
  textInput.value = <span class="hljs-string">""</span>;
  dateInput.value = <span class="hljs-string">""</span>;
  textarea.value = <span class="hljs-string">""</span>;
};
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8li973gq11jlrarl0nln.png" alt="Adding task cards" width="486" height="414" loading="lazy"></p>
<p>As you can see, there's no styles with the card. Let's add some styles: 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#tasks</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">14px</span>;
}

<span class="hljs-selector-id">#tasks</span> <span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid <span class="hljs-number">#abcea1</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#e2eede</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">4px</span>;
}
</code></pre>
<p>Style the edit and delete buttons with this code: 👇</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#tasks</span> <span class="hljs-selector-tag">div</span> <span class="hljs-selector-class">.options</span> {
  <span class="hljs-attribute">justify-self</span>: center;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-id">#tasks</span> <span class="hljs-selector-tag">div</span> <span class="hljs-selector-class">.options</span> <span class="hljs-selector-tag">i</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axe47wf6jutn330b5scn.png" alt="Styles card templates" width="578" height="452" loading="lazy"></p>
<h4 id="heading-function-to-delete-a-task">Function to delete a task</h4>
<p>Look here carefully, I added 3 lines of code inside the function.</p>
<ul>
<li>The first line will delete the HTML element from the screen,</li>
<li>the second line will remove the targetted Task from the data array,</li>
<li>and the third line will update the local storage with the new data.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> deleteTask = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.parentElement.parentElement.remove();

  data.splice(e.parentElement.parentElement.id, <span class="hljs-number">1</span>);

  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"data"</span>, <span class="hljs-built_in">JSON</span>.stringify(data));

  <span class="hljs-built_in">console</span>.log(data);
};
</code></pre>
<p>Now create a dummy task and try to delete it. The result so far looks like this: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qv50ozqjp239ldg0g21.gif" alt="Image description" width="792" height="780" loading="lazy"></p>
<h4 id="heading-function-to-edit-tasks">Function to edit tasks</h4>
<p>Look here carefully, I added 5 lines of code inside the function.</p>
<ul>
<li>Line 1 is targetting the task that we selected to edit</li>
<li>Lines 2, 3, and 4, are targetting the values [task, date, description] of the task that we selected to edit</li>
<li>line 5 is running the delete function to remove the selected data both from the local storage, HTML element, and data array.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> editTask = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> selectedTask = e.parentElement.parentElement;

  textInput.value = selectedTask.children[<span class="hljs-number">0</span>].innerHTML;
  dateInput.value = selectedTask.children[<span class="hljs-number">1</span>].innerHTML;
  textarea.value = selectedTask.children[<span class="hljs-number">2</span>].innerHTML;

  deleteTask(e);
};
</code></pre>
<p>Now, try to create a dummy task and edit it. The result so far: 👇</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nbxn7c7rs33chuafjca9.gif" alt="Editing a Task" width="792" height="780" loading="lazy"></p>
<h4 id="heading-how-to-get-data-from-local-storage">How to get data from local storage</h4>
<p>If you refresh the page, you'll note that all of your data is gone. In order to solve that issue, we run a IIFE (Immediately invoked function expression) to retrieve the data from local storage. Follow along: 👇</p>
<pre><code class="lang-js">(<span class="hljs-function">() =&gt;</span> {
  data = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"data"</span>)) || [];
  <span class="hljs-built_in">console</span>.log(data);
  createTasks();
})();
</code></pre>
<p>Now the data will show up even if you refresh the page.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tenojs64uefxutl7ysn.png" alt="Congratulations" width="1280" height="555" loading="lazy"></p>
<p>Congratulations for successfully completing this tutorial. You've learned how to create a todo list application using CRUD operations. Now, you can create your own CRUD application using this tutorial.</p>
<p>Here's your medal for reading until the end. ❤️</p>
<h2 id="heading-suggestions-amp-criticisms-are-highly-appreciated">Suggestions &amp; Criticisms Are Highly Appreciated ❤️</h2>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/usxsz1lstuwry3jlly4d.png" alt="Alt Text" width="1000" height="245" loading="lazy"></p>
<ul>
<li><a target="_blank" href="https://www.linkedin.com/in/joyshaheb/">LinkedIn/ JoyShaheb</a></li>
<li><a target="_blank" href="https://www.youtube.com/c/joyshaheb">YouTube / JoyShaheb</a></li>
<li><a target="_blank" href="https://twitter.com/JoyShaheb">Twitter / JoyShaheb</a></li>
<li><a target="_blank" href="https://www.instagram.com/joyshaheb/">Instagram / JoyShaheb</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform CRUD Operations using Angular 13 ]]>
                </title>
                <description>
                    <![CDATA[ By Nishant Kumar Building a full-stack application can be tough. And the base of building such an application is learning how to perform CRUD operations – Create, Read, Update, and Delete.  It's by using these operations that we manage the data flow ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-perform-crud-operations-using-angular-13/</link>
                <guid isPermaLink="false">66d4605d230dff0166905833</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 14 Mar 2022 19:49:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/How-to-Build-a-Weather-Application-using-React--82-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nishant Kumar</p>
<p>Building a full-stack application can be tough. And the base of building such an application is learning how to perform CRUD operations – Create, Read, Update, and Delete. </p>
<p>It's by using these operations that we manage the data flow between the client application and the server.</p>
<p>So, in this article, you'll learn how to perform CRUD operations in Angular using Angular Services.</p>
<p>Let's dive in.</p>
<h2 id="heading-but-what-are-angular-services">But What are Angular Services?</h2>
<p>Angular Services are methods that are triggered when we want to perform a certain operation in an Angular Application. In our case, they are the methods that will perform CRUD Operations. In other words, we will have a service that will Create data in the database. Just like that, we will have difference services for Reading Data from the server, Updating data in the server, as well as deleting data.</p>
<h2 id="heading-base-setup">Base Setup</h2>
<p>Create a folder called Angular CRUD in your system. And inside that folder, create two files. One is the client, and the other is the server.</p>
<p>The <strong>client</strong> will contain our Angular Application, and the <strong>server</strong> will have the backend code for the server, built using Node, Express, and MongoDB.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-185153.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want to learn how to design and develop a RESTful API, you can watch my video on <a target="_blank" href="https://youtu.be/paxagc55loU">RESTful APIs - Build a RESTful API using Node, Express, and MongoDB</a>. You can also refer my blog on <a target="_blank" href="https://www.freecodecamp.org/news/build-a-restful-api-using-node-express-and-mongodb/">How to Build a RESTful API Using Node, Express, and MongoDB</a>.</p>
<p>But if you want just the code, you can just get it from <a target="_blank" href="https://github.com/nishant-666/Rest-Api-Express-MongoDB">GitHub</a>.</p>
<p>Add this backend code in the server folder, and then run it using <strong>npm start</strong>. Don't forget the use <strong>npm install</strong> to install the packages first.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-185814.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, in the client folder, add the starter code for the Angular Project from the repository below. It's just a form that prints the name and age in the console. </p>
<p>Do an <strong><code>npm i</code></strong> here as well before running the project. And to run the project, just do <strong><code>ng serve</code></strong>.</p>
<p>Angular Stater Code: <a target="_blank" href="https://github.com/nishant-666/Angular-crud/tree/Stater-Code">https://github.com/nishant-666/Angular-crud/tree/Stater-Code</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-190334.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And here is our output which has two inputs and a submit button.</p>
<h2 id="heading-how-to-write-services-for-crud-operations">How to Write Services for CRUD Operations</h2>
<p>Now, let's write services for the CRUD Operations. But we need to generate a service component first. Let's call this services <strong>users</strong>.</p>
<p>To generate a new service, simply type the following command in a new terminal:</p>
<pre><code>ng g s users
</code></pre><p>Here, <strong>g</strong> is short for generate and <strong>s</strong> is short for service, followed by the service name, which is users.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-190732.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And the service has now been created. You can check the newly created service into the <strong>app</strong> folder.</p>
<pre><code><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;

@Injectable({
  <span class="hljs-attr">providedIn</span>: <span class="hljs-string">'root'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsersService</span> </span>{

  <span class="hljs-keyword">constructor</span>() { }
}
</code></pre><p>Now, let's write the code for the read service that gets data from the database. For that, we need the <strong>HttpClientModule</strong>, in order to send or receive <strong>http requests.</strong></p>
<p>We will do it into the <strong>app.module.ts</strong>, because that's where all the imports are.</p>
<pre><code><span class="hljs-keyword">import</span> { HttpClientModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;
</code></pre><p>And then add this <strong>HttpClientModule</strong> in the list of imports:</p>
<pre><code>imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
 ],
</code></pre><p>Here is the whole <strong>app.module.ts</strong> for your reference:</p>
<pre><code><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { BrowserModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/platform-browser'</span>;
<span class="hljs-keyword">import</span> { FormsModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/forms'</span>;
<span class="hljs-keyword">import</span> { AppRoutingModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app-routing.module'</span>;
<span class="hljs-keyword">import</span> { AppComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.component'</span>;
<span class="hljs-keyword">import</span> { HttpClientModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;

@NgModule({
  <span class="hljs-attr">declarations</span>: [
    AppComponent
  ],
  <span class="hljs-attr">imports</span>: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  <span class="hljs-attr">providers</span>: [],
  <span class="hljs-attr">bootstrap</span>: [AppComponent]
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{ }
</code></pre><p>Now, we can send <strong>http</strong> requests from our application.</p>
<p>To receive data from the backend, let's create a service. Into the users.service.ts, import <strong>HttpClient</strong> and <strong>Observable.</strong> </p>
<pre><code><span class="hljs-keyword">import</span> { HttpClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;
<span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
</code></pre><p>So, we will send requests to the backend API using this <strong>HttpClient</strong>, and we will receive the incoming data using an <strong>observable.</strong></p>
<p>Now, let's create an instance of HttpClient in the constructor.</p>
<pre><code><span class="hljs-keyword">constructor</span>(private http: HttpClient) { }
</code></pre><p>Let's also define the base URL for the backend API. If you check the server folder, you will see a file called <strong>index.js.</strong> And here, we have this base endpoint <strong>/api</strong>.</p>
<pre><code>private baseURL = <span class="hljs-string">`http://localhost:3000/api`</span>
</code></pre><pre><code>app.use(<span class="hljs-string">'/api'</span>, routes)
</code></pre><h2 id="heading-how-to-create-a-service-for-getting-the-data">How to Create a Service for Getting the Data</h2>
<p>Create a function that will run every time we send a <strong>GET</strong> request to the server.</p>
<pre><code>getAllData(): Observable&lt;any&gt; {
   <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.get(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.baseURL}</span>/getAll`</span>)
}
</code></pre><p>This <strong>getAll</strong> is the route for the getting all the data. So, we are appending the <strong>baseURL</strong> with the route path.</p>
<p>Now, we have to call this function wherever we want to show the incoming data. Let's do it in the <strong>app.component.ts.</strong></p>
<p>First, import the service.</p>
<pre><code><span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
</code></pre><p>Then, create an instance of this service in the constructor.</p>
<pre><code><span class="hljs-keyword">constructor</span>(
    private userService: UsersService
  ) { }
</code></pre><p>Then, in <strong>ngOnInit</strong>, call the function in the <strong>userService</strong>. Also, subscribe to the incoming data using <strong>subscribe</strong>.</p>
<pre><code>ngOnInit() {
    <span class="hljs-built_in">this</span>.userService.getAllData()
      .subscribe(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(data)
      })
  }
</code></pre><p>So, this <strong>ngOnInit</strong> runs when the page loads, which is the equivalent of the <strong>useEffect Hook</strong> and <strong>componentDidMount</strong> in React.</p>
<p>And this subscribe returns us the incoming data from the backend server.</p>
<p>Now, let's check the console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-192702.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We don't have any data in the database, that's why we are getting an empty array.</p>
<h2 id="heading-how-to-create-a-service-for-adding-data">How to Create a Service for Adding Data</h2>
<p>Now, let's create a service for adding some data to the backend database using the backend server.</p>
<pre><code>postData(data: any): Observable&lt;any&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.post(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.baseURL}</span>/post`</span>, data)
}
</code></pre><p>This is very similar to the read service. The only difference is that it takes two arguments, not one. One is the endpoint, and the other is the data which we are going to post. And we will pass this data from our <strong>app.component.ts.</strong></p>
<p>In the <strong>app.component.ts</strong> file, create a function submitData. It should contain a body object that will be sent.</p>
<pre><code> submitData(value: any) {
    <span class="hljs-keyword">let</span> body = {
      <span class="hljs-attr">name</span>: value.name,
      <span class="hljs-attr">age</span>: value.age
    }
  }
</code></pre><p>Then, we will post this body like this:</p>
<pre><code><span class="hljs-built_in">this</span>.userService.postData(body)
  .subscribe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response)
})
</code></pre><p>So, think about it like this. We are sending the body in the userService.postData function, and it's getting received on the other end as <strong>data</strong> arguments, in the services. And then, we are simply posting it.</p>
<pre><code>postData(data: any): Observable&lt;any&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.post(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.baseURL}</span>/post`</span>, data)
}
</code></pre><p>Here is the whole submitData function for your reference:</p>
<pre><code>submitData(value: any) {
    <span class="hljs-keyword">let</span> body = {
      <span class="hljs-attr">name</span>: value.name,
      <span class="hljs-attr">age</span>: value.age
    }

    <span class="hljs-built_in">this</span>.userService.postData(body)
      .subscribe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response)
      })
  }
</code></pre><p>Now, let's add some data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-193534.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Add some name and age, and click Add Data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-193610.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And it will be added. Refresh the page, and you will see that the read data service is working as well, because we will be getting the incoming data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-193645.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-create-a-service-for-updating-and-deleting-data">How to Create a Service for Updating and Deleting Data</h2>
<p>Now, let's create the services for updating and deleting data.</p>
<pre><code>updateData(data: any, <span class="hljs-attr">id</span>: string): Observable&lt;any&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.patch(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.baseURL}</span>/update/<span class="hljs-subst">${id}</span>`</span>, data)
}
</code></pre><p>So, this <strong>updateData</strong> service takes two arguments. One is the id of the document we are going to update, and the second is the new data that will replace the previous data. The <strong>updateData</strong> uses the patch method to update the data.</p>
<p>We will use the id as path parameters. It will be appended in the <strong>http.patch</strong> method. And we will pass the new data, too.</p>
<p>Similarly, we have the <strong>deleteData</strong> service. This only takes the id as arguments, and it will be removed. The <strong>deleteData</strong> uses the <code>delete</code> method to delete the data.</p>
<pre><code>deleteData(id: string): Observable&lt;any&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.http.delete(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.baseURL}</span>/delete/<span class="hljs-subst">${id}</span>`</span>)
}
</code></pre><p>Import the updateData function into the <strong>app.component.ts</strong> file.</p>
<pre><code>updateData(value: any) {
    <span class="hljs-keyword">let</span> body = {
      <span class="hljs-attr">name</span>: value.name,
      <span class="hljs-attr">age</span>: value.age
    }

    <span class="hljs-built_in">this</span>.userService.updateData(body, <span class="hljs-string">`622ca8c59f6c668226f74f52`</span>)
      .subscribe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response)
      })
  }
</code></pre><p>Here, we're passing the new updated body and the id of the document that we want to update.</p>
<pre><code>&lt;form #loginForm=<span class="hljs-string">"ngForm"</span> (ngSubmit)=<span class="hljs-string">"updateData(loginForm.value)"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-fields"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">ngModel</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-field"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-fields"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"age"</span> <span class="hljs-attr">ngModel</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Age"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"age"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-field"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Update Data <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/form&gt;
</code></pre><p>Also, change the function in <strong>app.component.html</strong> as well, in the form tags.</p>
<p>So, if we add some new data in the input fields, it will replace the old data for the id <strong>622ca8c59f6c668226f74f52.</strong> Because that is the data and id we are passing.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-194634.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's add this new data in the form, and click the Update Data button. You will see that the data will be updated and it will be in the console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-194708.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To delete data, create a function in app.component.ts called <strong>delete,</strong> and add the <strong>deleteData</strong> service inside it. </p>
<pre><code><span class="hljs-keyword">delete</span>() {
    <span class="hljs-built_in">this</span>.userService.deleteData(<span class="hljs-string">`622c573cf23ce54e445b2bed`</span>)
      .subscribe(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response);
      })
  }
</code></pre><p>Also, change the HTML button text and the function. </p>
<pre><code>&lt;form #loginForm=<span class="hljs-string">"ngForm"</span> (ngSubmit)=<span class="hljs-string">"delete()"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-fields"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">ngModel</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-field"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-fields"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"age"</span> <span class="hljs-attr">ngModel</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Age"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"age"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-field"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Delete Data <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/form&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-195125.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open the Newtork tab in Chrome Dev Tools, and click the Delete Data button. It will delete the document with the id of <strong>622ca8c59f6c668226f74f52,</strong> because that is what we are passing to the <strong>deleteData</strong> service.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-12-195807.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And we will get this confirmation message.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>So, that is how we do <strong>CRUD operations</strong> in Angular 13 using Services.</p>
<p>You can also check my video on <a target="_blank" href="https://youtu.be/O-MAtagUJjM">Let's perform CRUD Operations with Angular 13 - Full Tutorial for Beginners</a></p>
<p>Get the full code here: <a target="_blank" href="https://github.com/nishant-666/Angular-crud/tree/Finished-Code">https://github.com/nishant-666/Angular-crud/tree/Finished-Code</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
