<?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[ REST API - 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[ REST API - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 22:29:48 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/rest-api/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Scoped Note-Taking API with Django Rest Framework and SimpleJWT ]]>
                </title>
                <description>
                    <![CDATA[ If you've built a Django API and you're wondering how to add authentication so that each user can only access their own data, you're in the right place. Most Django tutorials teach you session-based a ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-scoped-note-taking-api-with-django-rest-framework-and-simplejwt/</link>
                <guid isPermaLink="false">69fa4395a386d7f121cd3bfc</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Blogs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ django rest framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Prabodh Tuladhar ]]>
                </dc:creator>
                <pubDate>Tue, 05 May 2026 19:23:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/36921ffa-4741-4e11-8f16-2c84322ebceb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've built a Django API and you're wondering how to add authentication so that each user can only access their own data, you're in the right place.</p>
<p>Most Django tutorials teach you session-based authentication. That works fine when your frontend and backend live on the same server. But the moment you separate them – say, a React app on Netlify talking to a Django API on PythonAnywhere – then sessions start to break down.</p>
<p>Cookies don't travel well across different domains, and suddenly your login system stops working.</p>
<p>That's where JSON Web Tokens (JWT) come in. JWTs give you a stateless, cookie-free way to authenticate users. They work seamlessly across domains, devices, and platforms. The server doesn't need to remember anything. It just verifies the token's signature and knows exactly who's making the request.</p>
<p>But authentication is only half the problem. Once you know who a user is, you still need to control what they can see. This is where <strong>scoping</strong> comes in.</p>
<p>Scoping means ensuring that each user can only access their own data. User A should never be able to read, edit, or delete User B's data (notes in our case), even if they somehow guess the right ID.</p>
<p>In this tutorial, you'll build a a personal note-taking API where users can register, log in with JWT tokens, and store notes that only they can access.</p>
<p>Along the way, you'll implement a custom user model, configure SimpleJWT for token-based authentication, and write scoped views that lock each user's data behind their own credentials.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-prerequisities">Prerequisities</a></p>
</li>
<li><p><a href="#heading-what-is-jwt-and-why-use-it-over-session-authentication">What is JWT and Why Use It Over Session Authentication</a>?</p>
<ul>
<li><p><a href="#heading-how-session-authentication-works">How Session Authentication Works</a></p>
</li>
<li><p><a href="#heading-how-jwt-authentication-works">How JWT Authentication Works</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-1-how-to-set-up-the-project-and-install-the-dependecies">Step 1: How to Set Up the Project and Install the Dependecies</a></p>
<ul>
<li><p><a href="#heading-11-how-to-create-the-project">1.1 How to Create the Project</a></p>
</li>
<li><p><a href="#heading-12-how-to-create-a-virtual-environment-and-install-the-required-dependencies">1.2 How to Create a Virtual Environment and Install the Required Dependencies</a></p>
</li>
<li><p><a href="#heading-13-how-to-create-the-project-and-the-app">1.3 How to Create the Project and the App</a></p>
</li>
<li><p><a href="#heading-14-how-to-register-the-app-and-django-rest-framework-drf">1.4 How to Register the App and Django Rest Framework (DRF)</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-2-how-to-create-a-custom-user-model">Step 2: How to Create a Custom User Model</a></p>
<ul>
<li><p><a href="#heading-21-how-to-define-the-custom-user-model">2.1 How to Define the Custom User Model</a></p>
</li>
<li><p><a href="#heading-22-how-to-tell-django-to-use-your-custom-user-model">2.2 How to Tell Django to Use Your Custom User Model</a></p>
</li>
<li><p><a href="#heading-23-how-to-run-migrations">2.3 How to Run Migrations</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-3-how-to-define-the-note-model">Step 3: How to Define the Note Model</a></p>
<ul>
<li><p><a href="#heading-32-how-to-apply-migration">3.2 How to Apply Migration</a></p>
</li>
<li><p><a href="#heading-33-how-to-register-models-in-the-admin">3.3 How to Register Models in the Admin</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-4-how-to-create-the-serializer">Step 4: How to Create the Serializer</a></p>
<ul>
<li><p><a href="#heading-41-how-to-create-userserializer">4.1 How to Create UserSerializer</a></p>
</li>
<li><p><a href="#heading-42-how-to-create-noteserializer">4.2 How to Create NoteSerializer</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-5-how-to-configure-simplejwt">Step 5: How to Configure SimpleJWT</a></p>
<ul>
<li><p><a href="#heading-51-how-to-update-rest-framework-settings">5.1 How to Update REST Framework Settings</a></p>
</li>
<li><p><a href="#heading-52-how-to-add-token-url-endpoints">5.2 How to Add Token URL Endpoints</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-6-how-to-build-the-authentication-logic">Step 6: How to Build the Authentication Logic</a></p>
</li>
<li><p><a href="#heading-step-7-how-to-implement-scoped-views">Step 7: How to Implement Scoped Views</a></p>
<ul>
<li><p><a href="#heading-71-how-to-create-a-noteviewset">7.1 How to Create a NoteViewSet</a></p>
</li>
<li><p><a href="#heading-72-why-this-matters-preventing-id-enumeration-attacks">7.2 Why This Matters: Preventing ID Enumeration Attacks</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-8-how-to-connect-a-url">Step 8: How to Connect a URL</a></p>
<ul>
<li><p><a href="#heading-81-how-to-create-app-level-urls">8.1 How to Create App-level URLs</a></p>
</li>
<li><p><a href="#heading-82-how-to-verify-the-project-level-urls">8.2 How to Verify the Project-Level URLs</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-9-how-to-test-the-apis-with-postman">Step 9: How to Test the APIs with Postman</a></p>
<ul>
<li><p><a href="#heading-91-how-to-register-a-user">9.1 How to Register a User</a></p>
</li>
<li><p><a href="#heading-92-how-to-obtain-access-and-refresh-tokens">9.2 How to Obtain Access and Refresh Tokens</a></p>
</li>
<li><p><a href="#heading-93-how-to-create-a-note">9.3 How to Create a Note</a></p>
</li>
<li><p><a href="#heading-94-how-to-list-your-notes">9.4 How to List Your Notes</a></p>
</li>
<li><p><a href="#heading-95-how-to-demostrate-scoping">9.5 How to Demostrate Scoping</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-step-10-how-to-handle-token-expiration-with-refresh-tokens">Step 10: How to Handle Token Expiration with Refresh Tokens</a></p>
</li>
<li><p><a href="#heading-how-you-can-improve-this-project">How You Can Improve This Project</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>Here's what this tutorial covers:</p>
<ol>
<li><p>How to set up a custom user model (and why you should always do this)</p>
</li>
<li><p>How to configure SimpleJWT for access and refresh token authentication</p>
</li>
<li><p>How to build serializers that protect sensitive fields</p>
</li>
<li><p>How to scope your API views so users only see their own data</p>
</li>
<li><p>How to test the entire flow using Postman</p>
</li>
</ol>
<p>Let's get started</p>
<h2 id="heading-prerequisities">Prerequisities</h2>
<p>Before you begin, make sure you're comfortable with the following:</p>
<ol>
<li><p><strong>Django fundamentals</strong>: You should understand how Django projects and apps work, including models, views, URLs, and migrations.</p>
</li>
<li><p><strong>Django REST Framework basics</strong>: You should be familiar with serializers, viewsets or API views, and how DRF handles requests and responses.</p>
</li>
<li><p><strong>Basic command line usage</strong>: You'll run commands in your terminal throughout this tutorial.</p>
</li>
</ol>
<p>Tools you'll need installed:</p>
<ul>
<li><p>Python 3.8 or higher</p>
</li>
<li><p>pip (Python's package manager)</p>
</li>
<li><p>A code editor like Visual Studio Code</p>
</li>
<li><p>Postman (or any API testing tool) for testing your endpoints. You'll use this to send requests to your API.</p>
</li>
</ul>
<h2 id="heading-what-is-jwt-and-why-use-it-over-session-authentication">What is JWT and Why Use It Over Session Authentication?</h2>
<p>Before you write any code, it's important to understand what problem JWTs solve and why Django's built-in session authentication isn't always enough.</p>
<h3 id="heading-how-session-authentication-work">How Session Authentication Work</h3>
<p>Django ships with a session-based authentication system. Here's how it works at a high level:</p>
<ol>
<li><p>A user sends their username and password to the server.</p>
</li>
<li><p>The server verifies the credentials and creates a <strong>session</strong> which is a small record stored in the server's database that says "this user is logged in."</p>
</li>
<li><p>The server sends back a <strong>session ID</strong> as a cookie. The browser stores this cookie automatically.</p>
</li>
<li><p>On every subsequent request, the browser sends the cookie back to the server. The server looks up the session ID in its database and says "ah, this is User A. Let them through."</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/2689a08a-f8a9-4b83-ad7b-cc4c2de90419.png" alt="The infographics shows the steps taken in Django session authentication" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This works perfectly when your frontend and backend live on the same domain. The browser handles cookies automatically, and Django manages sessions in the database without you thinking about it.</p>
<p>But this approach has some limitations.</p>
<ol>
<li><p><strong>The cross-domain problem:</strong> If your React frontend lives at app.example.com and your Django API lives at <a href="http://api.example.com">api.example.com</a>, cookies become tricky. Browsers enforce strict rules about which domains can send and receive cookies.</p>
<p>You can work around this with CORS (Cross-Origin Resource Sharing) headers and special cookie settings, but it adds complexity and can be fragile.</p>
</li>
<li><p><strong>The scalability problem:</strong> Every active session is stored in the server's database. If you have 10,000 users logged in at the same time, that's 10,000 session records the server has to look up on every single request. As your application grows, this lookup becomes a bottleneck.</p>
</li>
<li><p><strong>The mobile problem:</strong> Mobile apps don't handle cookies the same way browsers do. If you're building an API that will serve both a web app and a mobile app, session cookies create extra headaches.</p>
</li>
</ol>
<h3 id="heading-how-jwt-authentication-works">How JWT Authentication Works</h3>
<p>JWTs take a fundamentally different approach. Instead of storing session data on the server, they put the authentication information directly into the token itself.</p>
<p>Here's how the flow works:</p>
<ol>
<li><p>A user sends their username and password to the server.</p>
</li>
<li><p>The server verifies the credentials and creates a JWT – a long encoded string that contains information like the user's ID and when the token expires.</p>
</li>
<li><p>The server sends this token back to the client. The client stores it (usually in memory or local storage).</p>
</li>
<li><p>On every subsequent request, the client includes the token in the request header. The server reads the token, verifies its signature, and says "this is User A. Let them through."</p>
</li>
</ol>
<p>Notice the key difference: <strong>the server never stores anything</strong>.</p>
<p>It doesn't look up a session in a database. It simply reads the token, checks its cryptographic signature to make sure nobody tampered with it, and extracts the user information. That's why JWTs are called <strong>stateless</strong> – the server doesn't maintain any state about who is logged in.</p>
<p><strong>This solves the cross-domain problem</strong> because tokens are sent in the request header, not as cookies. Headers work the same way regardless of which domain the request comes from.</p>
<p><strong>This solves the scalability problem</strong> because the server doesn't store sessions. Verifying a token is a quick cryptographic check, not a database lookup.</p>
<p><strong>This solves the mobile problem</strong> because any client that can send HTTP headers can use JWT. Mobile apps, desktop apps, other servers – they all work the same way.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/41d60dbd-707c-4483-8374-8910024bda7f.png" alt="The infographics shows the steps taken in JWT authentication" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-step-1-how-to-set-up-the-project-and-install-the-dependecies">Step 1: How to Set Up the Project and Install the Dependecies</h2>
<h3 id="heading-11-how-to-create-the-project">1.1 How to Create the Project</h3>
<p>Open your terminal, navigate to where you want your project to live, and run the following commands:</p>
<pre><code class="language-shell">mkdir notes-project

cd notes-project
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/594f6c90-ea92-4859-9d9b-442d2fd2f23d.png" alt="The image shows the creation of notes project folder" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-12-how-to-create-a-virtual-environment-and-install-the-required-dependencies">1.2 How to Create a Virtual Environment and Install the Required Dependencies</h3>
<p>You will create a virtual environment here. Type the following command:</p>
<pre><code class="language-shell">python3 -m venv venv
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/4c1c9c33-9ffb-433a-a8f0-60cf0f598e14.png" alt="The image shows the creation of the virtual environment folder after tying the command" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The above command creates a virtual environment inside a folder called <code>venv</code>. The first <code>venv</code> is the command and the second <code>venv</code> represents the name of the folder. You can name the folder anything though <code>venv</code> is usually preferred.</p>
<p>To activate the virtual environment, we need to use the following command:</p>
<p>On macOS/Linux:</p>
<pre><code class="language-shell">source venv/bin/activate
</code></pre>
<p>On Windows:</p>
<pre><code class="language-shell">venv\Scripts\activate
</code></pre>
<p>You'll know it worked when you see <code>(venv)</code> at the beginning of your terminal prompt. From this point on, any Python packages you install will only exist inside this <strong>virtual environment</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/0a58f106-684c-4286-91fc-3c60f6e45483.png" alt="The image shows virtual environment being activated" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>With the virutal environment activated, install Django, Django Rest Framework, and Simple JWT Framework using the command:</p>
<pre><code class="language-shell">pip install django djangorestframework djangorestframework-simplejwt 
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/af83ad3f-3201-4e59-9367-e95630ae3cb3.png" alt="The image shows the installation of the packages after running the pip command" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You can verify everything installed correctly by running:</p>
<pre><code class="language-shell">pip list
</code></pre>
<p>You should see all three packages listed along with their dependencies.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b725778c-57ca-42cb-a0a2-486ec3e6286e.png" alt="The image shows a list of all the dependencies along with the dependencies installed just now" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-13-how-to-create-the-project-and-the-app">1.3 How to Create the Project and the App</h3>
<p>Run the following command to create the Django project:</p>
<pre><code class="language-plaintext">django-admin startproject notes_core .
</code></pre>
<p>The dot at the end is important. It tells Django to create the project files in your current directory instead of creating an extra nested folder.</p>
<p>Now let's type this command to create the app:</p>
<pre><code class="language-shell">python manage.py startapp notes
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f0f95ce1-b8b0-4acb-ae5a-194fa3d74e08.png" alt="The image shows the folder structure of django project and app" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-14-how-to-register-the-app-and-django-rest-framework-drf">1.4 How to Register the App and Django Rest Framework (DRF)</h3>
<p>Open <code>notes_core/settings.py</code> and add <code>rest_framework</code> and <code>notes</code> in the <code>INSTALLED_APPS</code> list:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/35988eff-506c-43af-ac6c-ef698e843ad3.png" alt="The image show the DRF and notes app being added to installed app list" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Django now knows about your new app and the REST framework. Let's move on to the most important architectural decision you'll make for this project.</p>
<h2 id="heading-step-2-how-to-create-a-custom-user-model">Step 2: How to Create a Custom User Model</h2>
<p>If you've built Django projects before, you might have used Django's default User model. For quick prototypes, that works fine. But for any project you plan to grow or maintain, starting with a custom user model is a best practice you should never skip.</p>
<p>Here's why: Django's default <code>User</code> model uses a <code>username</code> field as the primary identifier. If you later decide you want users to log in with their email address instead, or you need to add a profile picture field, or a phone number, then you're stuck.</p>
<p>Using a custom user model gives you full control over what a "user" means in your app. Instead of being tied to a username, you can design login around something more practical, like email or phone_number for a fitness or mobile-based app. You can also include fields like role (doctor, patient, receptionist in a clinic system) or date of birth directly in the user model, instead of managing a separate profile.</p>
<p>It also helps future-proof your project. If you start with the default model and later decide to switch login from username to email, or add required fields, it becomes difficult and risky to change. Using a custom user model from the beginning avoids this problem and makes it much easier to adapt your authentication system as your app grows.</p>
<p>By creating a custom user model from the start, even if it's identical to the default one, you give yourself the freedom to make changes later without any of that pain.</p>
<h3 id="heading-21-how-to-define-the-custom-user-model">2.1 How to Define the Custom User Model</h3>
<p>Open <code>notes/models/py</code> and add the following code:</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    pass
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/29310f13-cdc9-409a-9c36-23234882fd6e.png" alt="The image shows the code for the custom user model" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You are importing Django’s built-in <code>AbstractUser</code> class.</p>
<p>Think of <code>AbstractUser</code> as a ready-made blueprint for a user. It already includes fields like username, password, email, first name, last name , and authentication logic.</p>
<p>The <code>pass</code> statement means you're not adding any extra fields yet.</p>
<p>But the key point is that this model is yours. So this model behaves exactly like Django’s default user model, but with one <strong>big advantage</strong>: you now have the flexibility to customize it later.</p>
<p>If three months from now you need to add a <code>phone_number</code> field or switch to email-based login, you just add a field to this class and run a migration.</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    phone_number = models.CharField(max_length=15)
</code></pre>
<p>You can also see all the fields that the <code>CustomUser</code> class has inherited from the <code>AbstractUser</code> class.</p>
<p>To do this we can use the Python shell. Type the following command:</p>
<pre><code class="language-shell">python manage.py shell
</code></pre>
<p>When you type this command, make sure that the virtual environment is active:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3c958f7f-6403-4eaf-b339-43532a02af6a.png" alt="The image shows the command to enter into the python shell with the virtual environment being activated" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>After this, import the <code>CustomUser</code> model in the shell:</p>
<pre><code class="language-shell">from notes.models import CustomUser
</code></pre>
<p>After that, type the following code:</p>
<pre><code class="language-shell">[fields.name for field in CustomUser._meta.get_fields()]
</code></pre>
<p>The above statement lists out all the fields in the <code>CustomUser</code> class.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/5a1b3314-7b48-41f6-98a9-dc3133cfce4c.png" alt="The image shows the output of all the fileds inherited by the CustomUser model" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-22-how-to-tell-django-to-use-your-custom-user-model">2.2 How to Tell Django to Use Your Custom User Model</h3>
<p>Now comes the important bit. Open <code>notes_core/settings.py</code> and add this line:</p>
<pre><code class="language-python">AUTH_USER_MODEL = 'notes.CustomUser'
</code></pre>
<p>This setting tells Django to use your <code>CustomUser</code> model instead of the built-in one for everything authentication-related such as login, permissions, foreign keys, and so on.</p>
<p>There's no strict rule to where you need to add it, but the best practice is to add it near the end of the file.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/87c9b03c-908d-4b2d-a6d5-9528ff98d1ab.png" alt="The image shows the above code being added to the settings.py file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You can see which user model Django is using by using the method <code>get_user_model()</code>.</p>
<p>Open the Python shell again and import the <code>get_user_model()</code> method:</p>
<pre><code class="language-shell">from django.contrib.auth import get_user_model 
</code></pre>
<p>Then use <code>get_user_model()</code> and print the output:</p>
<pre><code class="language-shell">user = get_user_model()
print(user)
</code></pre>
<p>You should see the name of our model being used:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/895d5bcc-6880-4c4d-9007-96d44e9fa496.png" alt="895d5bcc-6880-4c4d-9007-96d44e9fa496" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>If you hadn't added the <code>AUTH_USER_MODEL</code> in the <code>settings.py</code> file, then Django would have used the default user model:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a89f013a-e5d8-4e59-90b8-7da594188c13.png" alt="The image shows the default user model being used by Django" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p><strong>Note:</strong> You'll need to do this before you run your first migration. If you run migrate before setting AUTH_USER_MODEL, Django creates tables for the default User model, and switching afterward becomes a headache.</p>
<h3 id="heading-23-how-to-run-migrations">2.3 How to Run Migrations</h3>
<p>Now create and apply the initial migrations:</p>
<pre><code class="language-shell">python manage.py makemigrations
python manage.py migrate
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cbca499a-286c-4f07-9a3e-375a69b4c374.png" alt="The image shows the output after running the above commands" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Django will create the necessary tables for your custom user model along with all the built-in Django tables.</p>
<p>We can again peek under the hood to see the SQL queries that Django used to create the tables especially the <code>CustomUser</code> table.</p>
<p>Type this command:</p>
<pre><code class="language-shell">python manage.py sqlmigrate notes 0001
</code></pre>
<p>Here <code>notes</code> is the name of the app and <code>0001</code> represents the migration number.</p>
<p>And you should get this output:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/850bba6c-8e54-4beb-8b85-f30f193341d5.png" alt="The image shows the output after the sqlmigrate command is executed" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Let's also create a superuser so you can access the admin panel later for debugging:</p>
<pre><code class="language-shell">python manage.py createsuperuser
</code></pre>
<p>Fill in the username, email (optional), and password when prompted.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/43820470-86b4-4274-834a-19a97adbc208.png" alt="The image shows the super user being created" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-step-3-how-to-define-the-note-model">Step 3: How to Define the Note Model</h2>
<p>Now let's create the data model for the core of your application. First add a new import to use the <code>settings</code> object.</p>
<pre><code class="language-python">from django.conf import settings
</code></pre>
<p>Then add the following code below the <code>CustomUser</code> class:</p>
<pre><code class="language-python">class Notes(models.Model):
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='notes'
    )
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return f"{self.title} (by {self.owner.username})"
</code></pre>
<p>Here's the complete <code>model.py</code> code:</p>
<pre><code class="language-python">from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings

class CustomUser(AbstractUser):
    pass

class Notes(models.Model):
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='notes'
    )
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return f"{self.title} (by {self.owner.username})"
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/24f1c5e3-6f9a-4dce-a7dc-d5d17aecc202.png" alt="The image shows the complete models.py file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Let's walk through each field:</p>
<ol>
<li><p><code>owner = models.ForeignKey(settings.AUTH_USER_MODEL, ...)</code>: Creates a relationship between each note and a user. The <code>ForeignKey</code> field tells Django that each note belogs to exactly one user but a user can have many notes.</p>
<p>Notice that we use <code>settings.AUTH_USER_MODEL</code> instead of directly importing <code>CustomUser</code>. This is the recommended practice because it keeps your code flexible. If you ever change the user model reference in settings, this foreign key adapts automatically.</p>
<p>The <code>on_delete=models.CASCADE</code> means that if a user is deleted, all their notes are deleted too.</p>
<p>The <code>related_name='notes'</code> lets you access a user's notes with <code>user.notes.all()</code>.</p>
</li>
<li><p><code>title = models.CharField(max_length=200)</code>: Creates a text field for the task name, limited to 200 characters.</p>
</li>
<li><p><code>body = models.TextField()</code>: Holds the actual note content. <code>TextField</code> has no character limit, so users can write as much as they need.</p>
</li>
<li><p><code>created_at = models.DateTimeField(auto_now_add=True)</code>: Automatically records the date and time when a task is created. You never need to set this manually.</p>
<p>The <code>__str__()</code> method gives each note a readable representation. Instead of seeing "Note object (1)" in the admin panel or during debugging, you'll see something like "Meeting Notes (by Solina)."</p>
</li>
</ol>
<h3 id="heading-32-how-to-apply-migration">3.2 How to Apply Migration</h3>
<p>Run the migration commands to create the Note table:</p>
<pre><code class="language-shell">python manage.py makemigrations
python manage.py migrate
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/bf4b3469-89d8-4f8b-8b0d-1ea24eda5e2e.png" alt="The image shows the result of migrating the notes model" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>As before, we can see the exact SQL query Django used to create the <code>notes</code> table:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/606d0d20-7c4f-40fb-a37b-de623ccee574.png" alt="The image shows the SQL query to create the notes table  and reference to the custom user table created earlier" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-33-how-to-register-models-in-the-admin">3.3 How to Register Models in the Admin</h3>
<p>Open <code>notes/admin.py</code> and register both models so you can inspect data through the admin panel:</p>
<pre><code class="language-python">from django.contrib import admin
from .models import CustomUser, Notes

admin.site.register(CustomUser)
admin.site.register(Notes)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/482fc6de-33d2-4d09-8c6f-ce3df684eaa3.png" alt="The image shows the code for admin.py" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>This is helpful during development when you want to quickly check whether data is being saved correctly.</p>
<h2 id="heading-step-4-how-to-create-the-serializer">Step 4: How to Create the Serializer</h2>
<p>In DRF, a serializer is like a bridge between your database and the internet.</p>
<p>Django models store data as Python objects. But when you want to send that data to a frontend application (like React or a mobile app), you can't send Python objects. You need to send a format that everyone understands which is usually JSON.</p>
<p>Serializers perform three main jobs:</p>
<ol>
<li><p><strong>Serialization:</strong> Converting complex Python objects (Models) into Python dictionaries (which can be easily rendered into JSON).</p>
</li>
<li><p><strong>Deserialization:</strong> Converting JSON data coming from a user back into complex Python objects.</p>
</li>
<li><p><strong>Validation:</strong> Checking if the incoming data is correct before saving it to the database.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a7339d6d-e338-4e12-a837-a780e85752a6.png" alt="The image shows the serialization deserialization process" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-41-how-to-create-userserializer">4.1 How to Create UserSerializer</h3>
<p>Create a new file called <code>notes/serializers.py</code> and add the following code:</p>
<pre><code class="language-python">from rest_framework import serializers
from django.contrib.auth import get_user_model

User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password']

    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            email=validated_data.get('email', ''),
            password=validated_data['password']
        )
        return user
</code></pre>
<p>Let's break down this serializer.</p>
<ol>
<li><p>The <code>UserSerializer</code> handles user registration.</p>
</li>
<li><p><code>User = get_user_model()</code> gets the user model that you're using and stores in the variable <code>User</code>. In our case, we're using the <code>CustomUser</code> model</p>
</li>
<li><p><code>class UserSerializer(serializers.ModelSerializer):</code>: Here you've created the UserSerializer class, which inherits <code>ModelSerializer</code>.</p>
<p>A <code>ModelSerializer</code> is a shortcut that automatically creates a serializers class with fields that are in the model class.</p>
<p>When we use a <code>ModelSerializer</code>, DRF inspects the model and automatically does these things:</p>
<p>1. Generates fields from the model so you don't have to<br>2. Automatically adds field validations that are present in the model<br>3. Implements <code>create()</code> and <code>update()</code> methods. A <code>ModelSerializer</code> knows which model to use and how to update and create it. You can override <code>create()</code> and <code>update()</code> methods if you need customized behaviors. <strong>You have overridden the</strong> <code>create()</code> <strong>method in the above code.</strong></p>
</li>
<li><p><code>password = serializers.CharField(write_only=True)</code>: This line is crucial. The <code>write_only=True</code> flag means the password will be accepted during registration but will <strong>never</strong> appear in any API response. Without this, your API would send back the password (even if hashed) every time user data is returned.</p>
<p>So users can create accounts, but their passwords are never exposed back.</p>
</li>
<li><p><code>class Meta</code>: Inside the <code>Meta</code> class, you tell the serializer which model to use. In this case, the model to use is <code>User</code> and the fields to be handled.</p>
</li>
<li><p>The <code>create()</code> method: This is the most important part. This method runs when we create a new user. Instead of using the default <code>.create()</code> method you have overridden it.</p>
<p>It's important to understand why we have overridden this method. The default <code>create()</code> method is not suitable for creating users securely.</p>
<p>By default this method stores the password in plain text format. This is a serious problem because passwords should never be stored in raw form. They need to be <strong>hashed</strong> so that even if the database is compromised, the passwords are never exposed.</p>
<p>Django provides a special method called <code>create_user()</code> that automatically handles this by <strong>hashing the password</strong> and setting up the user properly for authentication.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c1246e5d-104d-486c-965c-8edb04c850dc.png" alt="The image shows the annoated explanation of the code above" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-42-how-to-create-noteserializer">4.2 How to Create NoteSerializer</h3>
<p>After the <code>UserSerializer</code> class, let's create the <code>NoteSerializer</code> class. The <code>NoteSerializer</code> handles the notes data</p>
<p>First of all, you need to add an import to the <code>Notes</code> class. Add the line <code>from .models import Notes</code> at the end of the last import.</p>
<p>Put this code below the <code>UserSerializer</code> class:</p>
<pre><code class="language-python">class NoteSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    class Meta:
        model = Notes
        fields = ['id', 'owner', 'title', 'body', 'created_at']
</code></pre>
<p>Now let's break it down:</p>
<ol>
<li><p><code>owner = serializers.ReadOnlyField(source='owner.username')</code>: This is the most important line in the code. This makes the <code>owner</code> field <strong>read-only</strong>. That means the API will display who owns a note (showing their username), but no one can set or change the owner through the API.</p>
<p>Without this protection, a malicious user could send a POST request with <code>"owner": 5</code> and assign their note to someone else's account, or worse, modify someone else's notes by reassigning ownership.</p>
<p>The <code>source='owner.username'</code> part tells DRF to display the owner's username instead of their numeric ID, which makes the API responses more readable.</p>
</li>
<li><p><code>class Meta:</code> ...: As before the <code>Meta</code> class contains the model which the serializer use and the fields that the API will expose.</p>
<p>Here is the complete code in the <code>serializers.py</code> file</p>
</li>
</ol>
<pre><code class="language-python">from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Notes

User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password']

    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            email=validated_data.get('email', ''),
            password=validated_data['password']
        )
        return user

class NoteSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    class Meta:
        model = Notes
        fields = ['id', 'owner', 'title', 'body', 'created_at']
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/3073f560-79dc-4950-8acb-96d871e0511c.png" alt="The image shows the complete code for the serializers.py file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-step-5-how-to-configure-simplejwt">Step 5: How to Configure SimpleJWT</h2>
<p>Now let's set up the authentication system. This is where you tell DRF to use JWT for authentication instead of sessions. This step is crucial because without it, DRF will default to session-based auth.</p>
<p>SimpleJWT provides a complete JWT implementation for DRF, so you don't have to build token generation, signing, or verification from scratch.</p>
<p>The access token is what your client sends with every API request. It's short-lived by design. Think of it like a visitor badge at an office building: it gets you through the door, but it expires at the end of the day. If someone steals it, the damage is limited because it stops working soon.</p>
<p>The refresh token is longer-lived and has a single purpose: getting a new access token when the current one expires. The client stores it securely and only sends it to one specific endpoint. Think of it like your employee ID card. You use it to get a new visitor badge each morning, but you don't flash it at every door.</p>
<p>This separation exists for security. If the short-lived access token is compromised (which is more likely since it's sent with every request), the attacker has a narrow window before it expires. The refresh token, which is sent less frequently, has a lower risk of interception.</p>
<p>Let's look at how the access and refresh token work together</p>
<ol>
<li><p>User logs in, server gives both access token and refresh token</p>
</li>
<li><p>User makes requests using the access token</p>
</li>
<li><p>Access token expires</p>
</li>
<li><p>App sends refresh token to server</p>
</li>
<li><p>Server checks it and gives a new access token</p>
</li>
<li><p>User continues without logging in again</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/9cf61a53-99c6-4665-bf5d-dccafa71ca8d.png" alt="The image shows the use of access and refresh tokens" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-51-how-to-update-rest-framework-settings">5.1 How to Update REST Framework Settings</h3>
<p>Open <code>notes_core/settings.py</code> and add the following code:</p>
<pre><code class="language-python">from datetime import timedelta
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),

    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/54e89c41-b456-4bbb-a129-ac3e92a09a6d.png" alt="The image shows the code being added to settings.py file" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Let's unpack what each section does.</p>
<p>The <code>DEFAULT_AUTHENTICATION_CLASSES</code> setting tells DRF to use JWT as the authentication method for all API endpoints. Every incoming request will be checked for a valid JWT token in the Authorization header.</p>
<p>The <code>DEFAULT_PERMISSION_CLASSES</code> setting sets <code>IsAuthenticated</code> as the global permission policy. This means every endpoint in your API is locked down by default. Only users with a valid token can access any endpoint.</p>
<p>This is a secure-by-default approach: instead of remembering to protect each view individually, everything is protected, and you explicitly open up the endpoints that need to be public <em>(like the registration endpoint, which you'll handle in the next step).</em></p>
<p>The <code>SIMPLE_JWT</code> dictionary controls token behavior. The access token lasts 30 minutes. This is the token clients include in every request. If someone intercepts it, the damage is limited to a 30-minute window. The refresh token lasts one day.</p>
<p>When the access token expires, the client can use the refresh token to get a new access token without forcing the user to log in again. The duration of the refresh token is 1 day. This means after 1 day, the user must log in again with their username and password. You'll see exactly how this works later when you test with Postman.</p>
<h3 id="heading-52-how-to-add-token-url-endpoints">5.2 How to Add Token URL Endpoints</h3>
<p>SimpleJWT provides ready-made views for obtaining and refreshing tokens. You just need to wire them up to URLs.</p>
<p>Open <code>notes_core/urls.py</code> and update it with the following code:</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('notes.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
</code></pre>
<p>The <code>token/</code> endpoint accepts a username and password, and returns an access token and a refresh token.</p>
<p>The <code>token/refresh/</code> endpoint accepts a refresh token and returns a new access token. You'll see these in action during testing.</p>
<h2 id="heading-step-6-how-to-build-the-authentication-logic">Step 6: How to Build the Authentication Logic</h2>
<p>Open <code>notes/views.py</code> and add the following:</p>
<pre><code class="language-python">from rest_framework import generics, permissions
from django.contrib.auth import get_user_model
from .serializers import UserSerializer

User = get_user_model()

class RegisterView(generics.CreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [permissions.AllowAny]
</code></pre>
<p>Now let's walk through this code.</p>
<p>The first section are the imports and after that we have used the the <code>get_user_model()</code> method to get the <code>CustomUser</code> model.</p>
<p>Now the main part is <code>RegisterView</code> class. The class inherits from <code>generics.CreateAPIView</code> which is a built in DRF view designed specifically for handling POST requests that create new objects.</p>
<p>Because of this, you don’t have to manually write the logic for handling POST requests, validating data, or saving to the database. DRF does all of that for you behind the scenes.</p>
<p>Inside the class, <code>queryset = Users.objects.all()</code> defines the set of user objects this view can work with.</p>
<p>The <code>serializer_class = UserSerializer</code> tells the view which serializer to use for validating incoming data and creating the user.</p>
<p>Finally <code>permission_classes = [permissions.AllowAny]</code> overrides the global <code>IsAuthenticated</code> permission you set earlier in the value of <code>DEFAULT_PERMISSION_CLASSES</code> .</p>
<p>This means that anyone can access the registration endpoint, even if they aren't logged in. This makes sense for a registration endpoint because new users won’t have accounts yet.</p>
<p>Every other view in your API will inherit the global IsAuthenticated permission, so only this registration endpoint is open.</p>
<h2 id="heading-step-7-how-to-implement-scoped-views">Step 7: How to Implement Scoped Views</h2>
<p>This is the heart of the tutorial. You've set up authentication so the API knows <strong>who</strong> is making a request. Now you need to make sure each user can only interact with <strong>their</strong> <strong>own</strong> notes.</p>
<p>Think of it this way: authentication is the lock on the front door of an apartment building. It keeps strangers out. But scoping is the lock on each individual apartment. Just because you live in the building doesn't mean you can walk into your neighbor's apartment.</p>
<p>Without scoping, an authenticated user could potentially see every note in the database, or worse, modify notes that belong to someone else. Two method overrides on your viewset prevent this entirely.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/03747660-068c-4757-9fc2-d2a122f22f5f.png" alt="The image represents the differences of access resources with and without scoping" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-71-how-to-create-a-noteviewset">7.1 How to Create a NoteViewSet</h3>
<p>Now let's create the <code>NoteViewSet</code>. First add these imports to the top of the file. We're importing the viewsets, serializers, and model.</p>
<pre><code class="language-python">from .models import Note
from .serializers import UserSerializer, NoteSerializer
from rest_framework import generics, viewsets, permissions
</code></pre>
<p>Add the following to <code>notes/views.py</code>, below the RegisterView:</p>
<pre><code class="language-python">class NoteViewSet(viewsets.ModelViewSet):
    serializer_class = NoteSerializer

    def get_queryset(self):
        return Notes.objects.filter(owner=self.request.user).order_by('-created_at')

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
</code></pre>
<p>Now let's talk about this code in detail.</p>
<p>You've created a new class called <code>NoteViewSet</code> which inherits from the DRF class <code>ModelViewSet</code>. This gives you full CRUD operations, meaning you can list notes and retrieve a single note, as well as create, update, and delete a note.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/25999ad8-3534-424a-ab35-cad9cecec8ef.png" alt="The image shows the Model Viewset being imported" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The next part <code>serializer_class = NoteSerializer</code> tells Django to use the <code>NoteSerializer</code> class to convert between Python objects and JSON.</p>
<p>But the magic is the two methods that you are overriding: <code>get_queryset()</code> and <code>perform_create()</code>.</p>
<p>The <code>get_queryset()</code> method controls which notes the API returns. If you didn't override this method, it would return <code>Note.objects.all()</code> (which would give every user access to every note in the database).</p>
<p>But here, you've overridden this method so that it filters notes by the current user.</p>
<p>Next is the <code>perform_create()</code> method, which is called when the note is saved. You've overridden this method so that it saves the notes of the user who's currently logged in. If you hadn't overridden the this method, it would return all the notes regardless of the logged in user.</p>
<p>Notice that you have passed <code>self.request.user</code> parameters in to the <code>filter()</code> function. This is the code that attaches the logged-in user as the owner of the note.</p>
<p>Remember how you made the owner field read-only in the serializer? This is the other half of that security measure.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/6db94c2f-673f-480a-bf20-730ed4af4bdb.png" alt="6db94c2f-673f-480a-bf20-730ed4af4bdb" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The user can't set the owner through the API request, and the server automatically sets it to whoever is authenticated. These two pieces work together to make ownership tamper-proof.</p>
<h3 id="heading-72-why-this-matters-preventing-id-enumeration-attacks">7.2 Why This Matters: Preventing ID Enumeration Attacks</h3>
<p>Without get_queryset filtering, your API might allow something like this: a user sends a GET request to <code>/api/notes/42/</code> and sees a note that belongs to someone else, simply because they guessed the ID.</p>
<p>This is called an <strong>ID enumeration attack</strong> — an attacker cycles through IDs (1, 2, 3, 4...) to discover and access other people's data.</p>
<p>With your scoped <code>get_queryset</code>, even if User B sends a request to <code>/api/notes/42/</code> and note 42 belongs to User A, the viewset won't find it in User B's filtered queryset. DRF will return a 404 — as far as User B is concerned, that note doesn't exist.</p>
<h2 id="heading-step-8-how-to-connect-a-url">Step 8: How to Connect a URL</h2>
<p>Now you need to wire up the views to URL paths so the API knows which view to call for each endpoint.</p>
<h3 id="heading-81-how-to-create-app-level-urls">8.1 How to Create App-level URLs</h3>
<p>Create a new file called <code>notes/urls.py</code> and add the following:</p>
<pre><code class="language-python">from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import RegisterView, NoteViewSet

router = DefaultRouter()
router.register(r'notes', NoteViewSet, basename='note')

urlpatterns = [
    path('register/', RegisterView.as_view(), name='register'),
    path('', include(router.urls)),
]
</code></pre>
<p>The <code>DefaultRouter</code> automatically generates URL patterns for the NoteViewSet. Since you're using a <code>ModelViewSet</code>, the router creates endpoints for listing all notes, creating a note, retrieving a single note, updating a note, and deleting a note — <strong>all from that single router.register call.</strong></p>
<p>The <code>basename='note'</code> parameter is required here because your viewset doesn't have a queryset attribute defined directly on the class <em>(you're using get_queryset instead)</em>. DRF uses the <code>basename</code> to generate the URL pattern names like <code>note-list</code> and <code>note-detail</code>.</p>
<h3 id="heading-82-how-to-verify-the-project-level-urls">8.2 How to Verify the Project-Level URLs</h3>
<p>Make sure your <code>notes_core/urls.py</code> looks like this (you set this up in Step 5, but let's confirm):</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('notes.urls')),
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
</code></pre>
<p>Here's the full picture of your API's URL structure:</p>
<table>
<thead>
<tr>
<th><strong>Endpoint</strong></th>
<th><strong>Method</strong></th>
<th><strong>Description</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>api/register/</code></td>
<td><strong>POST</strong></td>
<td>Create a new user account</td>
</tr>
<tr>
<td><code>api/token/</code></td>
<td><strong>POST</strong></td>
<td>Get access and refresh tokens</td>
</tr>
<tr>
<td><code>api/token/refresh/</code></td>
<td><strong>POST</strong></td>
<td>Get a new access token using a refresh token</td>
</tr>
<tr>
<td><code>api/notes/</code></td>
<td><strong>GET</strong></td>
<td>List all notes for the authenticated user</td>
</tr>
<tr>
<td><code>api/notes/</code></td>
<td><strong>POST</strong></td>
<td>Create a new note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>GET</strong></td>
<td>Retrieve a specific note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>PUT/PATCH</strong></td>
<td>Update a specific note</td>
</tr>
<tr>
<td><code>api/notes/&lt;id&gt;/</code></td>
<td><strong>DELETE</strong></td>
<td>Delete a specific note</td>
</tr>
</tbody></table>
<p>Start the development server to make sure everything runs without errors:</p>
<pre><code class="language-shell">python manage.py runserver
</code></pre>
<p>If the server starts without complaints, your code is wired up correctly.</p>
<h2 id="heading-step-9-how-to-test-the-apis-with-postman">Step 9: How to Test the APIs with Postman</h2>
<p>Building the API is one thing. Proving it works is another. Let's walk through the entire flow using Postman, from registering a user to demonstrating that scoping actually works.</p>
<p>If you haven't used Postman before, it's a tool that lets you send HTTP requests to your API and inspect the responses. You can download it from <a href="https://www.postman.com/downloads/">postman.com/downloads</a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/cc154f8b-d3db-4c48-b884-1dbd3d517209.png" alt="Postman software download page" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Alternatively, you can use curl from the command line or any other API testing tool you're comfortable with.</p>
<p>Make sure your development server is running before proceeding.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/90524445-9d7c-43d0-bcf7-105f54626d85.png" alt="python server running" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-91-how-to-register-a-user">9.1 How to Register a User</h3>
<p>Open Postman:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8951a205-ee01-4646-8e0b-d1d16d21c749.png" alt="opening Postman" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Create a new request:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/register/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ "username": "priya", "email": "<a href="mailto:priya@example.com">priya@example.com</a>", "password": "securepassword123" }</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f043164f-184c-4f29-8a9f-55f604d521fb.png" alt="postman UI for registering a new user" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Click <strong>Send</strong>. You should get a <code>201 Created</code> response with the user data <strong>(without the password</strong>, thanks to your <code>write_only=True</code> field) which you wrote in the <code>UserSerializer</code> class.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/021a79db-418f-4057-97f8-f3c5c4b9761c.png" alt="response of registering a user" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/c8fd6b4e-f539-4f16-85c8-72515abadf8f.png" alt="The image describes the codes of the User serializer classs" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-92-how-to-obtain-access-and-refresh-tokens">9.2 How to Obtain Access and Refresh Tokens</h3>
<p>Now log in to get your JWTs:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/token/</code></td>
</tr>
<tr>
<td><strong>Body</strong></td>
<td>{"username" : "priya", "password" : "securepassword123"}</td>
</tr>
</tbody></table>
<p>You'll get a response with access and refresh tokens.</p>
<p><strong>Copy the access token.</strong> You'll need it for every subsequent request. Also save the refresh token, as you'll use it later.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e5667e26-b11a-463e-85d4-ba99082bee21.png" alt="The image shows the api returning access and refresh token" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>A JWT is only encoded and not encrypted. The encoding is merely a way to transform the data into a safe, standard string format that can be easily transmitted over the internet.</p>
<p>Any one can peel through the encoding to see the data. This is done using base64url encoding.</p>
<p>We can use the Python library <code>pyjwt</code> to decode JWTs or use any of the online sites to decode. It's important to note that you should use online sites with caution since JWTs may contain sensitive information.</p>
<p>For this demo, we'll use site called <a href="https://www.jwt.io">jwt.io</a>.</p>
<p>Open the site and paste in the access token that you have just created:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f8b9f3e0-db1e-49fb-82be-2b4d27adc8bd.png" alt="The image describes the various sections after decoding the JWT token" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The JWT has three parts: the header, the payload, and the signature.</p>
<p>The header sections tells you how the header is signed. In this case it is signed using the <strong>HS256</strong> algorithm.</p>
<p>The payload is where the actual data or claim lives. It contains standard claims such as token types, expiration time ( <code>exp</code> ), issued at time ( <code>iat</code> ), and custom claims.</p>
<p>The signature section is used to verify integrity. You <strong>can't decode it to meaningful data.</strong> This section ensures that the token wasn't tampered with.</p>
<h3 id="heading-93-how-to-create-a-note">9.3 How to Create a Note</h3>
<p>Now use the access token to create a note:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/notes/</code></td>
</tr>
<tr>
<td><strong>Header tab:</strong></td>
<td>Add a new header:</td>
</tr>
<tr>
<td>Key: Authorization, Value: Bearer</td>
<td></td>
</tr>
<tr>
<td><strong>Body</strong></td>
<td>{'title': 'My note', 'body': 'This contains secret information'}</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/d04e2bfb-edc6-4c12-ac93-65611ed0d805.png" alt="The image shows adding new header into postman" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Notice that you don't include an owner field. That's handled automatically by perform_create. You should get a <code>201 Created response</code>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/19a8b564-4d49-4dc1-823c-d7d96fcb5319.png" alt="The image shows the output (response) after creating a note" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You can create a few more notes, so that we have some data to work with.</p>
<h3 id="heading-94-how-to-list-your-notes">9.4 How to List Your Notes</h3>
<p>Now to fetch all of Priya's notes:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>GET</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/notes/</code></td>
</tr>
<tr>
<td><strong>Header tab:</strong></td>
<td>Same Authorization: Bearer header</td>
</tr>
</tbody></table>
<p>You should see all the notes created, sorted by most recent first.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8b7107e6-44ef-465c-b1aa-076ec9de1979.png" alt="The image shows the response of getting list of notes" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-95-how-to-demonstrate-scoping">9.5 How to Demonstrate Scoping</h3>
<p>Let's prove that a second user can't view the first user's notes.</p>
<p>First, register the second user.</p>
<p>Send a POST request to <code>http://127.0.0.1/api/register</code> with the following data:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/register/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ "username": "sujan", "email": "<a href="mailto:sujan@example.com">sujan@example.com</a>", "password": "anotherpassword123" }</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/094af273-4220-416a-9c8f-f33079badf83.png" alt="The image shows a new user being created" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Then get tokens for Sujan by sending a POST request to <code>http://127.0.0.1:8000/api/token/</code> with Sujan's credentials (username and password) and then copy Sujan's access token.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/8fe22f1b-f36e-4b35-a478-1b48ea0218c3.png" alt="8fe22f1b-f36e-4b35-a478-1b48ea0218c3" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Now send a GET request to <code>http://127.0.0.1:8000/api/notes/</code> using Sujan's token in the Authorization header.</p>
<p>The response should be an empty list since this user hasn't created any notes:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/ef8e17d0-4f8f-4a51-8bfd-01c078247075.png" alt="The image shows the response of the get query new user's access token" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>More importantly, Priya's notes are completely invisible to him. Even if Sujan tries to access a specific note by ID – say, <code>http://127.0.0.1:8000/api/notes/1/</code> – he'll get a <code>404 Not Found</code> response, not a <code>403 Forbidden</code>.</p>
<p>This is intentional. A <code>404 Not Found</code> doesn't reveal that the note exists, while a <code>403 Forbidden</code> would confirm its existence to a potential attacker.</p>
<p>A <code>403 Forbidden</code> response is like a door with a sign: <em>“Authorized personnel only”.</em> You now know something important is inside. A <code>404 Not Found</code> response is like a blank wall. You don’t even know a room exists.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/a4619fbb-42ce-4f80-9207-31eb81336c7c.png" alt="The image shows the difference between a 403 and 404 response code" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Now that you know why we've used the <code>404</code> response instead of <code>403</code>, let's demonstrate this.</p>
<p>First, I'll access Priya's individual note using her credentials and her access token:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e68e33cc-93a4-4eb5-99fe-934b283defeb.png" alt="The image shows the result of accessing individual note using the first user (Priya)" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Now, I'll change the access token and put Sujan's (new user) access token:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/e5a6d07c-a7f0-4a50-ba05-94cc5159489c.png" alt="The image shows the response of accessing the second note using the new user's (sujan) credentials" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>You can see that using the new user's token to access the previous user's note leads to <code>404 Not Found</code> response.</p>
<h2 id="heading-step-10-how-to-handle-token-expiration-with-refresh-tokens">Step 10: How to Handle Token Expiration with Refresh Tokens</h2>
<p>Access tokens are deliberately short-lived (30 minutes in your configuration). This limits the window of damage if a token is stolen.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/b86f4f24-b8b0-45d0-bcee-5e39e2268e21.png" alt="b86f4f24-b8b0-45d0-bcee-5e39e2268e21" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>But you don't want users to re-enter their credentials every 30 minutes. That's what refresh tokens are for.</p>
<p>When Priya's access token expires, her API requests will start returning <code>401 Unauthorized</code> responses. Instead of logging in again, the client sends the refresh token to get a fresh access token.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL</strong></td>
<td><code>http://127.0.0.1:8000/api/token/refresh/</code></td>
</tr>
<tr>
<td><strong>Body tab</strong></td>
<td>Select "raw" and choose "JSON" from the dropdown</td>
</tr>
<tr>
<td><strong>Body Content</strong></td>
<td>{ refresh: &lt; Priya's refresh token &gt;}</td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/67d255ac-8696-45e6-be17-c80b2a6e8af0.png" alt="The image shows the response of getting a new access token using a refresh token" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Replace your old access token with this new one, and you're good for another 30 minutes. The refresh token itself lasts for one day, so the user only needs to fully log in again once every 24 hours.</p>
<p>In a real application, the frontend client handles this automatically. When an API call returns a <code>401</code>, the client catches it, sends the refresh token to get a new access token, and retries the original request — all without the user noticing.</p>
<p>Here's what that flow looks like in pseudocode:</p>
<ol>
<li><p>Client sends request with access token</p>
</li>
<li><p>Server responds with 401 (token expired)</p>
</li>
<li><p>Client sends refresh token to /api/token/refresh/</p>
</li>
<li><p>Server responds with a new access token</p>
</li>
<li><p>Client retries the original request with the new access token</p>
</li>
<li><p>Server responds with the data</p>
<img src="https://cdn.hashnode.com/uploads/covers/69bdd408475ca17974459537/f0fd3fd8-842b-4de3-8f5b-2f1d4ad2181f.png" alt="The image show the steps to get a new token after a previous one has expired" style="display:block;margin:0 auto" width="600" height="400" loading="lazy"></li>
</ol>
<p>If the refresh token itself has expired (after 24 hours in your configuration), step 4 will also return a <code>401</code>. At that point, the user truly needs to log in again with their username and password. This is the intended behavior: it means even a stolen refresh token has a limited useful life.</p>
<h2 id="heading-how-you-can-improve-this-project">How You Can Improve This Project</h2>
<p>This API is functional and secure, but there's plenty of room to build on it. Here are some directions you could take.</p>
<ol>
<li><p><strong>Add search and filtering.</strong> Let users search their notes by title or body text. You can use DRF's SearchFilter and django-filter to add query parameters like <code>?search=meeting</code> to the notes list endpoint.</p>
</li>
<li><p><strong>Add categories or tags.</strong> Create a <code>Category</code> model and add a <strong>foreign key</strong> to <code>Note</code>, or use a many-to-many relationship for tags. This would let users organize their notes and filter by category.</p>
</li>
<li><p><strong>Add pagination.</strong> Once a user has hundreds of notes, returning them all in a single response becomes slow. DRF has built-in pagination classes that let you return notes in pages of 10, 20, or whatever size you choose.</p>
</li>
<li><p><strong>Deploy to a production server.</strong> The API currently runs on your local machine. You could deploy it to platforms like PythonAnywhere, Railway, or Render to make it accessible from anywhere. You'd need to configure a production database (like PostgreSQL), set a secure SECRET_KEY, and serve the application behind HTTPS.</p>
</li>
<li><p><strong>Build a frontend.</strong> Connect a React, Next.js, or Vue.js frontend to this API. Store the JWTs in the client and implement the token refresh flow so users stay logged in seamlessly.</p>
</li>
<li><p><strong>Add token blacklisting.</strong> SimpleJWT supports token blacklisting, which lets you invalidate refresh tokens when a user logs out. Without this, a refresh token remains valid until it expires, even after the user "logs out."</p>
</li>
</ol>
<p>Each of these improvements builds on the patterns you've already learned and will deepen your understanding of Django, DRF, and API design.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've built a fully functional, secure note-taking API with Django, Django REST Framework, and SimpleJWT. Along the way, you learned some fundamental concepts that apply to any API you'll build in the future.</p>
<p>You started with a custom user model — a small decision at the beginning that saves you from a painful migration later. You configured JWT authentication so your API can serve mobile clients and decoupled frontends that can't rely on session cookies.</p>
<p>You built serializers that protect sensitive data by keeping passwords write-only and ownership read-only. Most importantly, you implemented scoped views that ensure each user's data is completely isolated from everyone else's.</p>
<p>The patterns you practiced here — overriding <code>get_queryset</code> to filter by the current user, overriding <code>perform_create</code> to assign ownership automatically, and using <code>read-only</code> fields to prevent data tampering — are the same patterns you'll use in production APIs handling real user data.</p>
<p>The best way to solidify what you've learned is to keep building. Try adding search and filtering, build a React frontend that consumes this API, or start a completely new project may be a task manager, a journal app, or a bookmarks API using the same JWT and scoping patterns. The core workflow stays the same. Only the models and business logic change.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Service-to-Service Communication: When to Use REST, gRPC, and Event-Driven Messaging ]]>
                </title>
                <description>
                    <![CDATA[ The communication layer is one of the few architectural decisions that touches everything in your apps. It determines your latency floor, how independently teams can deploy, how failures propagate, an ]]>
                </description>
                <link>https://www.freecodecamp.org/news/service-to-service-communication-when-to-use-rest-grpc-and-event-driven-messaging/</link>
                <guid isPermaLink="false">69dea59891716f3cfb76ac50</guid>
                
                    <category>
                        <![CDATA[ distributed system ]]>
                    </category>
                
                    <category>
                        <![CDATA[ service-to-service communication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abisoye Alli-Balogun ]]>
                </dc:creator>
                <pubDate>Tue, 14 Apr 2026 20:37:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/b56ca584-75e1-4d0f-a88a-c2419a0b5d6e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The communication layer is one of the few architectural decisions that touches everything in your apps. It determines your latency floor, how independently teams can deploy, how failures propagate, and how much pain you feel every time a contract needs to change.</p>
<p>There are three dominant patterns: REST over HTTP, gRPC with Protocol Buffers, and event-driven messaging through a broker. Most production systems use a mix of all three. The skill is knowing which pattern fits which interaction.</p>
<p>In this article, you'll learn the core mechanics of each communication style, the real trade-offs between them across five dimensions (latency, coupling, schema evolution, debugging, and operational complexity), and a decision framework for choosing the right pattern for each service interaction.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To get the most out of this article, you should be familiar with:</p>
<ul>
<li><p>Basic HTTP concepts (request/response, status codes, headers)</p>
</li>
<li><p>Working with APIs in any backend language (the examples use TypeScript and Node.js)</p>
</li>
<li><p>General understanding of microservices architecture</p>
</li>
<li><p>Familiarity with JSON as a data interchange format</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-the-three-patterns-at-a-glance">The Three Patterns at a Glance</a></p>
</li>
<li><p><a href="#heading-rest-the-default-choice">REST: The Default Choice</a></p>
</li>
<li><p><a href="#heading-grpc-the-performance-choice">gRPC: The Performance Choice</a></p>
</li>
<li><p><a href="#heading-event-driven-messaging-the-decoupling-choice">Event-Driven Messaging: The Decoupling Choice</a></p>
</li>
<li><p><a href="#heading-the-five-trade-off-dimensions">The Five Trade-Off Dimensions</a></p>
</li>
<li><p><a href="#heading-the-decision-framework">The Decision Framework</a></p>
</li>
<li><p><a href="#heading-hybrid-architectures-using-all-three">Hybrid Architectures: Using All Three</a></p>
</li>
<li><p><a href="#heading-schema-governance-at-scale">Schema Governance at Scale</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-the-three-patterns-at-a-glance">The Three Patterns at a Glance</h2>
<p>Before diving deep, here's the landscape:</p>
<table>
<thead>
<tr>
<th></th>
<th>REST</th>
<th>gRPC</th>
<th>Event-Driven</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Communication</strong></td>
<td>Synchronous</td>
<td>Synchronous (+ streaming)</td>
<td>Asynchronous</td>
</tr>
<tr>
<td><strong>Protocol</strong></td>
<td>HTTP/1.1 or HTTP/2</td>
<td>HTTP/2</td>
<td>Broker-dependent (TCP)</td>
</tr>
<tr>
<td><strong>Serialization</strong></td>
<td>JSON (typically)</td>
<td>Protocol Buffers (binary)</td>
<td>JSON, Avro, Protobuf</td>
</tr>
<tr>
<td><strong>Coupling</strong></td>
<td>Request-time</td>
<td>Request-time + schema</td>
<td>Temporal decoupling</td>
</tr>
<tr>
<td><strong>Best for</strong></td>
<td>Public APIs, CRUD</td>
<td>Internal high-throughput</td>
<td>Workflows, event sourcing</td>
</tr>
</tbody></table>
<p>Each has strengths, and none is universally better. The rest of this article explores why.</p>
<h2 id="heading-rest-the-default-choice">REST: The Default Choice</h2>
<p>REST over HTTP is the most widely understood communication pattern. Services expose resources at URL endpoints, and clients interact through standard HTTP methods.</p>
<pre><code class="language-typescript">// Order service calls the inventory service
async function checkInventory(productId: string): Promise&lt;InventoryStatus&gt; {
  const response = await fetch(
    `https://inventory-service/api/v1/products/${productId}/stock`,
    {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${getServiceToken()}`,
      },
    }
  );

  if (!response.ok) {
    throw new HttpError(response.status, await response.text());
  }

  return response.json();
}
</code></pre>
<h3 id="heading-where-rest-excels">Where REST Excels</h3>
<p>Every language, framework, and platform speaks HTTP. Your frontend, your mobile app, your partner integrations, and your internal services can all use the same protocol.</p>
<p>The tooling is also mature: load balancers, API gateways, caching proxies, and debugging tools all understand HTTP natively.</p>
<p>It's also relatively simple. A new developer can read a REST call and understand what it does. The URL describes the resource. The HTTP method describes the action. The status code describes the outcome. There's no schema compilation step, no code generation, and no special client library required.</p>
<p>Beyond this, HTTP has built-in caching semantics. A <code>GET /products/123</code> response with a <code>Cache-Control: max-age=60</code> header can be cached by every proxy between the caller and the server. gRPC and event-driven patterns have no equivalent built-in mechanism.</p>
<pre><code class="language-typescript">// REST response with cache headers
app.get("/api/v1/products/:id", async (req, res) =&gt; {
  const product = await getProduct(req.params.id);

  res.set("Cache-Control", "public, max-age=60");
  res.set("ETag", computeETag(product));

  res.json(product);
});
</code></pre>
<h3 id="heading-where-rest-falls-short">Where REST Falls Short</h3>
<p>REST's resource-oriented model often requires multiple round-trips to assemble a response. Fetching an order with its items, customer details, and shipping status might mean three separate HTTP calls. Each call adds network latency, TCP handshake overhead, and serialization cost.</p>
<pre><code class="language-typescript">// Three sequential calls to build one view
async function getOrderDetails(orderId: string): Promise&lt;OrderDetails&gt; {
  const order = await fetch(`/api/orders/${orderId}`).then((r) =&gt; r.json());
  const customer = await fetch(`/api/customers/${order.customerId}`).then((r) =&gt; r.json());
  const shipment = await fetch(`/api/shipments/${order.shipmentId}`).then((r) =&gt; r.json());

  return { order, customer, shipment };
}
</code></pre>
<p>You can mitigate this with composite endpoints or GraphQL, but that adds complexity. gRPC handles this more naturally with message composition.</p>
<p>The serialization overhead is also an issue. JSON is human-readable but expensive to parse. For high-throughput internal communication where nobody reads the payloads, you are paying a tax in CPU and bandwidth for readability you do not need.</p>
<p>Finally, there's no streaming. Standard REST is request-response. If you need the server to push updates to the client (real-time order tracking, live metrics), REST requires workarounds like polling, Server-Sent Events, or WebSockets. None of these are part of the REST model itself.</p>
<h2 id="heading-grpc-the-performance-choice">gRPC: The Performance Choice</h2>
<p>gRPC is a Remote Procedure Call framework built on HTTP/2 and Protocol Buffers. Instead of URLs and JSON, you define services and messages in <code>.proto</code> files, and the framework generates strongly-typed client and server code.</p>
<h3 id="heading-defining-the-contract">Defining the Contract</h3>
<pre><code class="language-protobuf">// inventory.proto
syntax = "proto3";

package inventory;

service InventoryService {
  // Unary: single request, single response
  rpc CheckStock(StockRequest) returns (StockResponse);

  // Server streaming: single request, stream of responses
  rpc WatchStockLevels(WatchRequest) returns (stream StockUpdate);

  // Client streaming: stream of requests, single response
  rpc BulkUpdateStock(stream StockAdjustment) returns (BulkUpdateResult);
}

message StockRequest {
  string product_id = 1;
  string warehouse_id = 2;
}

message StockResponse {
  string product_id = 1;
  int32 available = 2;
  int32 reserved = 3;
  google.protobuf.Timestamp last_updated = 4;
}

message StockUpdate {
  string product_id = 1;
  int32 available = 2;
  string warehouse_id = 3;
}
</code></pre>
<p>After running <code>protoc</code> (the Protocol Buffer compiler), you get generated client and server stubs in your target language. The TypeScript client looks like this:</p>
<pre><code class="language-typescript">import { InventoryServiceClient } from "./generated/inventory";
import { credentials } from "@grpc/grpc-js";

const client = new InventoryServiceClient(
  "inventory-service:50051",
  credentials.createInsecure()
);

async function checkStock(productId: string): Promise&lt;StockResponse&gt; {
  return new Promise((resolve, reject) =&gt; {
    client.checkStock(
      { productId, warehouseId: "warehouse-eu-1" },
      (error, response) =&gt; {
        if (error) reject(error);
        else resolve(response);
      }
    );
  });
}
</code></pre>
<h3 id="heading-where-grpc-excels">Where gRPC Excels</h3>
<p>Protocol Buffers serialize to a compact binary format. A message that is 1 KB as JSON might be 300 bytes as Protobuf. Combined with HTTP/2 multiplexing (multiple requests over a single TCP connection), gRPC delivers significantly lower latency and higher throughput than REST for internal service calls. And we all know performance is important.</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>REST (JSON/HTTP 1.1)</th>
<th>gRPC (Protobuf/HTTP 2)</th>
</tr>
</thead>
<tbody><tr>
<td>Serialization size</td>
<td>Larger (text-based JSON)</td>
<td>Significantly smaller (binary Protobuf)</td>
</tr>
<tr>
<td>Serialization time</td>
<td>Slower (JSON parse/stringify)</td>
<td>Faster (binary encode/decode)</td>
</tr>
<tr>
<td>Requests per connection</td>
<td>1 (without pipelining)</td>
<td>Multiplexed</td>
</tr>
<tr>
<td>Connection overhead</td>
<td>New connection per request (HTTP/1.1)</td>
<td>Persistent connections with multiplexing</td>
</tr>
</tbody></table>
<p>The exact improvement depends on payload size, network topology, and server implementation. In benchmarks, the difference ranges from marginal (tiny payloads on fast networks) to an order of magnitude (large payloads, high concurrency).</p>
<p>The takeaway: gRPC's binary serialization and HTTP/2 multiplexing give it a structural advantage for internal traffic, but you should measure in your own environment before making latency claims.</p>
<p>Also, gRPC natively supports four communication patterns: unary (request-response), server streaming, client streaming, and bidirectional streaming. This makes it a natural fit for real-time use cases like live stock updates, log tailing, or progress reporting.</p>
<pre><code class="language-typescript">// Server streaming: watch inventory changes in real time
function watchStockLevels(warehouseId: string): void {
  const stream = client.watchStockLevels({ warehouseId });

  stream.on("data", (update: StockUpdate) =&gt; {
    console.log(`Product \({update.productId}: \){update.available} available`);
  });

  stream.on("error", (error) =&gt; {
    console.error("Stream error:", error.message);
    // Reconnect logic here
  });

  stream.on("end", () =&gt; {
    console.log("Stream ended");
  });
}
</code></pre>
<p>Finally, it has strong typing across services. The <code>.proto</code> file is the single source of truth. Both the client and server are generated from it. If the inventory service changes the <code>StockResponse</code> message, the order service's build fails until it regenerates its client. You catch breaking changes at compile time, not at 3 AM.</p>
<h3 id="heading-where-grpc-falls-short">Where gRPC Falls Short</h3>
<p>The first key issue is browser support. Browsers can't make native gRPC calls because the browser's <code>fetch</code> API doesn't expose the HTTP/2 framing that gRPC requires (for example, trailers for status codes and fine-grained control over bidirectional streams).</p>
<p>You need gRPC-Web, which uses a proxy like Envoy to translate between the browser-compatible subset of gRPC and the full protocol. Alternatively, you can place a REST or GraphQL gateway in front of your gRPC services.</p>
<p>Either way, gRPC isn't a viable choice for any endpoint that a browser calls directly — which is why the decision framework in this article defaults to REST for public-facing APIs.</p>
<p>It's also difficult to debug. You can't <code>curl</code> a gRPC endpoint. The binary payloads aren't human-readable. Tools like <code>grpcurl</code> and Postman's gRPC support help, but the debugging experience is worse than inspecting a JSON response in a browser's network tab.</p>
<pre><code class="language-bash"># Debugging a REST endpoint
curl -s https://inventory-service/api/v1/products/abc-123/stock | jq

# Debugging a gRPC endpoint (requires grpcurl)
grpcurl -plaintext -d '{"product_id": "abc-123"}' \
  inventory-service:50051 inventory.InventoryService/CheckStock
</code></pre>
<p>Finally, operational overhead is an issue. You need to manage <code>.proto</code> files, run code generation in your build pipeline, version your proto definitions, and ensure all consumers regenerate when schemas change.</p>
<p>For a team with two services, this is manageable. For twenty services, you need a proto registry and a governance process.</p>
<h2 id="heading-event-driven-messaging-the-decoupling-choice">Event-Driven Messaging: The Decoupling Choice</h2>
<p>Event-driven communication flips the model. Instead of service A calling service B directly, service A publishes an event to a broker (Kafka, RabbitMQ, Amazon SNS/SQS, or similar), and service B consumes it asynchronously.</p>
<pre><code class="language-typescript">// Order service publishes an event after confirming an order
import { Kafka } from "kafkajs";

const kafka = new Kafka({ brokers: ["kafka:9092"] });
const producer = kafka.producer();

async function publishOrderConfirmed(order: Order): Promise&lt;void&gt; {
  await producer.send({
    topic: "order.confirmed",
    messages: [
      {
        key: order.id,
        value: JSON.stringify({
          eventType: "order.confirmed",
          eventId: crypto.randomUUID(),
          timestamp: new Date().toISOString(),
          data: {
            orderId: order.id,
            customerId: order.customerId,
            items: order.items.map((item) =&gt; ({
              productId: item.productId,
              quantity: item.quantity,
            })),
            total: order.total,
          },
        }),
      },
    ],
  });
}
</code></pre>
<pre><code class="language-typescript">// Inventory service consumes the event independently
const consumer = kafka.consumer({ groupId: "inventory-service" });

async function startInventoryConsumer(): Promise&lt;void&gt; {
  await consumer.subscribe({ topic: "order.confirmed" });

  await consumer.run({
    eachMessage: async ({ message }) =&gt; {
      const event = JSON.parse(message.value.toString());

      for (const item of event.data.items) {
        await decrementStock(item.productId, item.quantity);
      }

      logger.info("Inventory updated for order", {
        orderId: event.data.orderId,
      });
    },
  });
}
</code></pre>
<h3 id="heading-where-event-driven-excels">Where Event-Driven Excels</h3>
<p>First, it employs temporal decoupling. The producer doesn't wait for the consumer. The order service publishes "order confirmed" and moves on. If the inventory service is down, the event sits in the broker until it recovers. No timeout, no retry logic in the producer, no cascading failure.</p>
<p>One event can also trigger multiple independent reactions. When an order is confirmed, the inventory service decrements stock, the notification service sends a confirmation email, the analytics service records a conversion, and the shipping service starts fulfillment. The order service doesn't know or care about any of these consumers.</p>
<pre><code class="language-text">order.confirmed event
  ├── inventory-service    → Decrement stock
  ├── notification-service → Send confirmation email
  ├── analytics-service    → Record conversion
  └── shipping-service     → Create shipment
</code></pre>
<p>Adding a new consumer requires zero changes to the producer. This is the lowest coupling you can achieve between services.</p>
<p>There's also a natural audit trail. If your broker retains events (Kafka does this by default), you have a complete history of everything that happened. You can replay events to rebuild state, debug issues by examining the exact sequence of events, or spin up a new service that processes historical events to backfill its data.</p>
<h3 id="heading-where-event-driven-falls-short">Where Event-Driven Falls Short</h3>
<p>After the order service publishes "order confirmed," there's a window where the inventory service hasn't yet processed the event. During that window, a concurrent request might read stale stock levels. If your use case requires "read your own writes" consistency, event-driven communication alone is not enough.</p>
<pre><code class="language-typescript">// The problem: order confirmed, but stock not yet decremented
async function handleCheckout(cart: Cart): Promise&lt;Order&gt; {
  const order = await createOrder(cart);
  await publishOrderConfirmed(order);

  // If another request checks stock RIGHT NOW,
  // it sees the old (pre-decrement) value.
  // The inventory consumer hasn't processed the event yet.
  return order;
}
</code></pre>
<p>Debugging also gets more complex. When something goes wrong in a synchronous call chain, you get a stack trace. When something goes wrong in an event-driven flow, you get a message in a dead-letter queue and a question: which producer sent this? When? What was the system state at that time? Distributed tracing helps, but correlating events across services is fundamentally harder than following a request through a call stack.</p>
<p>You can also have issues with ordering guarantees. Most brokers guarantee ordering within a partition (Kafka) or a queue, but not globally. If the order service publishes "order confirmed" and then "order cancelled," the inventory service might process the cancellation first if the events land on different partitions.</p>
<pre><code class="language-typescript">// Use a consistent partition key to guarantee ordering per entity
await producer.send({
  topic: "order.events",
  messages: [
    {
      // All events for the same order go to the same partition
      key: order.id,
      value: JSON.stringify(event),
    },
  ],
});
</code></pre>
<p>Keying messages by entity ID (order ID, customer ID) ensures events for the same entity are processed in order. Events for different entities can be processed in parallel.</p>
<p>Finally, your operations get more complex. Running a message broker isn't free. Kafka requires ZooKeeper (or KRaft), topic management, partition rebalancing, consumer group coordination, and monitoring for consumer lag. Managed services like Amazon MSK, Confluent Cloud, or Amazon SQS reduce this burden but add cost.</p>
<h3 id="heading-handling-broker-failures">Handling Broker Failures</h3>
<p>What happens when the broker is unavailable? If your service writes to the database and then publishes an event, a broker outage means the event is lost even though the database write succeeded.</p>
<p>These patterns help:</p>
<h4 id="heading-1-the-outbox-pattern">1. The Outbox Pattern</h4>
<p>Instead of publishing directly to the broker, write the event to an "outbox" table in the same database transaction as your business data. A separate process (a poller or a change-data-capture connector like Debezium) reads the outbox table and publishes to the broker.</p>
<pre><code class="language-typescript">// Outbox pattern: write event to the database, not the broker
// db injected via dependency injection
async function confirmOrder(order: Order, db: Database): Promise&lt;void&gt; {
  await db.transaction(async (tx) =&gt; {
    // Business write and event write in the same transaction
    await tx.update("orders", { id: order.id, status: "confirmed" });
    await tx.insert("outbox", {
      id: crypto.randomUUID(),
      topic: "order.confirmed",
      key: order.id,
      payload: JSON.stringify({
        orderId: order.id,
        customerId: order.customerId,
        items: order.items,
        total: order.total,
      }),
      created_at: new Date(),
    });
  });
  // A separate relay process picks up outbox rows and publishes to Kafka
}
</code></pre>
<p>Because the event and the business data are written atomically, you never lose an event due to a broker outage. The relay process retries until the broker is back.</p>
<h4 id="heading-2-at-least-once-delivery">2. At-least-once delivery</h4>
<p>Most brokers guarantee at-least-once delivery, meaning consumers may see the same event more than once (for example, after a rebalance or a retry). Your consumers must be idempotent: processing the same event twice should produce the same result as processing it once.</p>
<pre><code class="language-typescript">// Idempotent consumer: use the eventId to deduplicate
async function handleOrderConfirmed(event: EventEnvelope&lt;OrderData&gt;): Promise&lt;void&gt; {
  const alreadyProcessed = await db.query(
    "SELECT 1 FROM processed_events WHERE event_id = $1",
    [event.eventId]
  );

  if (alreadyProcessed.rows.length &gt; 0) {
    logger.info("Duplicate event, skipping", { eventId: event.eventId });
    return;
  }

  await db.transaction(async (tx) =&gt; {
    await decrementStock(tx, event.data.items);
    await tx.insert("processed_events", {
      event_id: event.eventId,
      processed_at: new Date(),
    });
  });
}
</code></pre>
<p>The combination of the outbox pattern (producer side) and idempotent consumers (consumer side) gives you reliable event-driven communication even when the broker has intermittent failures.</p>
<h2 id="heading-the-five-trade-off-dimensions">The Five Trade-Off Dimensions</h2>
<p>Choosing a communication pattern isn't about which is "best." It's about which trade-offs you can accept for each specific interaction. Here are the five dimensions that matter most.</p>
<h3 id="heading-1-latency">1. Latency</h3>
<table>
<thead>
<tr>
<th>Pattern</th>
<th>Relative Latency</th>
<th>Why</th>
</tr>
</thead>
<tbody><tr>
<td>gRPC</td>
<td>Lowest</td>
<td>Binary serialization, HTTP/2 multiplexing, persistent connections</td>
</tr>
<tr>
<td>REST</td>
<td>Low-moderate</td>
<td>JSON parsing overhead, typically HTTP/1.1 connection setup</td>
</tr>
<tr>
<td>Event-driven</td>
<td>Highest (by design)</td>
<td>Broker write, replication, consumer poll interval</td>
</tr>
</tbody></table>
<p>Exact numbers depend on payload size, network hops, and infrastructure. The structural ordering is consistent: gRPC is fastest for synchronous calls, REST is close behind, and event-driven messaging trades latency for decoupling.</p>
<p>If the caller needs an immediate response (user-facing checkout, real-time search), use gRPC or REST. If the caller doesn't need the result right now (send email, update analytics), use events.</p>
<h3 id="heading-2-coupling">2. Coupling</h3>
<p>Coupling has two dimensions: <strong>temporal</strong> (does the caller wait for the receiver?) and <strong>schema</strong> (do they share a contract?).</p>
<table>
<thead>
<tr>
<th>Pattern</th>
<th>Temporal Coupling</th>
<th>Schema Coupling</th>
</tr>
</thead>
<tbody><tr>
<td>REST</td>
<td>High (caller blocks)</td>
<td>Low (JSON is flexible)</td>
</tr>
<tr>
<td>gRPC</td>
<td>High (caller blocks)</td>
<td>High (shared <code>.proto</code> files)</td>
</tr>
<tr>
<td>Event-driven</td>
<td>None (fire and forget)</td>
<td>Medium (shared event schema)</td>
</tr>
</tbody></table>
<p>REST's loose typing is a double-edged sword. You can add fields to a JSON response without breaking consumers (additive changes are safe). But you can also accidentally remove a field, and the consumer fails at runtime instead of compile time.</p>
<p>gRPC's strict typing catches breaking changes at build time, but it means every schema change requires regenerating clients. For two services, this is trivial. For twenty services consuming the same proto, you need a coordination process.</p>
<p>Event-driven messaging decouples in time but still couples on the event schema. If the <code>order.confirmed</code> event changes its structure, every consumer must handle both the old and new format during the transition.</p>
<h3 id="heading-3-schema-evolution">3. Schema Evolution</h3>
<p>Schema evolution is how you change the contract between services without breaking existing consumers. This is where the three patterns diverge most sharply.</p>
<h4 id="heading-rest-json">REST (JSON):</h4>
<pre><code class="language-typescript">// Version 1: price as a number
{ "productId": "abc-123", "price": 49.99 }

// Version 2: price as an object (breaking change)
{ "productId": "abc-123", "price": { "amount": 49.99, "currency": "USD" } }
</code></pre>
<p>JSON has no built-in versioning. You manage it through one of three strategies:</p>
<table>
<thead>
<tr>
<th>Strategy</th>
<th>How It Works</th>
<th>Trade-offs</th>
</tr>
</thead>
<tbody><tr>
<td><strong>URL versioning</strong> (<code>/api/v1/</code> vs <code>/api/v2/</code>)</td>
<td>Each version is a separate endpoint. Consumers opt in to the new version explicitly.</td>
<td>Simplest to understand. Duplicates route handlers. Hard to sunset old versions when many consumers pin to <code>/v1/</code>.</td>
</tr>
<tr>
<td><strong>Header versioning</strong> (<code>Accept: application/vnd.myapi.v2+json</code>)</td>
<td>Single URL, version negotiated via headers.</td>
<td>Cleaner URLs, no route duplication. Harder to test (you can't just paste a URL into a browser). Proxy and cache behavior is trickier since the response varies by header.</td>
</tr>
<tr>
<td><strong>Defensive parsing</strong> (consumer-side tolerance)</td>
<td>No explicit versioning. Consumers ignore unknown fields and use defaults for missing ones.</td>
<td>Zero coordination cost for additive changes. Breaks down for structural changes (field renames, type changes) where the consumer can't infer intent.</td>
</tr>
</tbody></table>
<p>Additive changes (new fields) are safe with any strategy. Structural changes (renaming fields, changing types) require explicit versioning — URL or header — so consumers can migrate at their own pace.</p>
<h4 id="heading-grpc-protocol-buffers">gRPC (Protocol Buffers):</h4>
<pre><code class="language-protobuf">// Protocol Buffers have built-in evolution rules
message StockResponse {
  string product_id = 1;
  int32 available = 2;
  int32 reserved = 3;
  // Field 4 was removed (never reuse field numbers)
  string warehouse_id = 5;       // New field: old clients ignore it
  optional string region = 6;    // Optional: old clients don't send it
}
</code></pre>
<p>Protocol Buffers handle evolution well by design. You can add new fields (old clients ignore them), deprecate fields (stop writing them, keep the number reserved), and use <code>optional</code> for fields that may not be present.</p>
<p>You can't rename fields, change field types, or reuse field numbers. These rules are enforced by the tooling.</p>
<h4 id="heading-event-driven-avrojson-schema">Event-driven (Avro/JSON Schema):</h4>
<p>For events, schema registries like Confluent Schema Registry enforce compatibility rules:</p>
<pre><code class="language-typescript">// Register a schema with backward compatibility
// New consumers can read old events, old consumers can read new events
const schema = {
  type: "record",
  name: "OrderConfirmed",
  fields: [
    { name: "orderId", type: "string" },
    { name: "customerId", type: "string" },
    { name: "total", type: "double" },
    // New field with default: backward compatible
    { name: "currency", type: "string", default: "USD" },
  ],
};
</code></pre>
<p>With a schema registry, producers can't publish events that violate the compatibility contract. This is the strongest governance model: the registry rejects incompatible schemas before they reach consumers.</p>
<h3 id="heading-4-debugging-and-observability">4. Debugging and Observability</h3>
<table>
<thead>
<tr>
<th>Pattern</th>
<th>Debugging Experience</th>
</tr>
</thead>
<tbody><tr>
<td>REST</td>
<td>Best. Human-readable payloads, browser DevTools, <code>curl</code>, standard HTTP tracing.</td>
</tr>
<tr>
<td>gRPC</td>
<td>Moderate. Binary payloads need <code>grpcurl</code> or Postman. Metadata is inspectable. Distributed tracing works well.</td>
</tr>
<tr>
<td>Event-driven</td>
<td>Hardest. Asynchronous flows require correlation IDs, dead-letter queue inspection, and broker-specific tooling.</td>
</tr>
</tbody></table>
<p>For event-driven systems, correlation IDs are essential:</p>
<pre><code class="language-typescript">// Always include a correlation ID in events
interface EventEnvelope&lt;T&gt; {
  eventId: string;
  eventType: string;
  correlationId: string; // Links related events across services
  causationId: string;   // The event that caused this one
  timestamp: string;
  source: string;
  data: T;
}

async function publishEvent&lt;T extends { entityId: string }&gt;(
  topic: string,
  type: string,
  data: T,
  correlationId: string,
  causationId?: string
): Promise&lt;void&gt; {
  const event: EventEnvelope&lt;T&gt; = {
    eventId: crypto.randomUUID(),
    eventType: type,
    correlationId,
    causationId: causationId ?? correlationId,
    timestamp: new Date().toISOString(),
    source: SERVICE_NAME,
    data,
  };

  await producer.send({
    topic,
    messages: [{ key: data.entityId, value: JSON.stringify(event) }],
  });
}
</code></pre>
<p>When investigating an issue, you search for the correlation ID across all services and reconstruct the full event chain. Without it, you're searching for a needle in a haystack.</p>
<h3 id="heading-5-operational-complexity">5. Operational Complexity</h3>
<table>
<thead>
<tr>
<th>Pattern</th>
<th>What You Operate</th>
</tr>
</thead>
<tbody><tr>
<td>REST</td>
<td>HTTP server, load balancer, API gateway</td>
</tr>
<tr>
<td>gRPC</td>
<td>gRPC server, proto registry, code generation pipeline, gRPC-Web proxy (if browser clients exist)</td>
</tr>
<tr>
<td>Event-driven</td>
<td>Message broker (Kafka/RabbitMQ/SQS), schema registry, dead-letter queues, consumer lag monitoring</td>
</tr>
</tbody></table>
<p>REST has the lowest operational overhead. Every team knows how to run an HTTP server.</p>
<p>gRPC adds a build-time dependency (proto compilation) and requires teams to learn new tooling.</p>
<p>Event-driven adds a runtime dependency (the broker) that must be highly available because if the broker goes down, inter-service communication stops.</p>
<h2 id="heading-the-decision-framework">The Decision Framework</h2>
<p>Use this framework when deciding how a specific pair of services should communicate. The answer is rarely one pattern for your entire system.</p>
<pre><code class="language-text">Does the caller need an immediate response?
├── Yes → Is this a public-facing or browser-accessible API?
│         ├── Yes → REST
│         └── No  → Is throughput or latency critical?
│                   ├── Yes → gRPC
│                   └── No  → REST (simpler, good enough)
└── No  → Can the caller tolerate eventual consistency?
          ├── No  → Use synchronous call (REST or gRPC) with async follow-up
          └── Yes → Does the event need to trigger multiple consumers?
                    ├── Yes → Event-driven messaging
                    └── No  → Is ordering critical?
                              ├── Yes → Event-driven with partition key
                              └── No  → Event-driven (or simple queue like SQS)
</code></pre>
<p>Some concrete examples:</p>
<table>
<thead>
<tr>
<th>Interaction</th>
<th>Pattern</th>
<th>Why</th>
</tr>
</thead>
<tbody><tr>
<td>Browser fetches product details</td>
<td>REST</td>
<td>Browser can't call gRPC natively, plus REST offers cacheability</td>
</tr>
<tr>
<td>Checkout validates payment in real time</td>
<td>gRPC</td>
<td>Low latency, strong typing, internal-only (no browser in the path)</td>
</tr>
<tr>
<td>Order confirmed triggers fulfillment</td>
<td>Event-driven</td>
<td>Multiple consumers, temporal decoupling</td>
</tr>
<tr>
<td>Frontend fetches user profile</td>
<td>REST</td>
<td>Simple CRUD, cacheable, browser-native</td>
</tr>
<tr>
<td>ML service scores recommendations</td>
<td>gRPC</td>
<td>High throughput, binary payloads, streaming</td>
</tr>
<tr>
<td>User signup triggers welcome email</td>
<td>Event-driven</td>
<td>Async, no need for immediate response</td>
</tr>
<tr>
<td>Service health checks</td>
<td>REST</td>
<td>Simplicity, universal tooling</td>
</tr>
<tr>
<td>Real-time stock level monitoring</td>
<td>gRPC streaming</td>
<td>Continuous updates, bidirectional if needed</td>
</tr>
</tbody></table>
<h2 id="heading-hybrid-architectures-using-all-three">Hybrid Architectures: Using All Three</h2>
<p>Most production systems use a combination. Here's a pattern that works well:</p>
<pre><code class="language-text">┌──────────┐    REST     ┌──────────────┐    gRPC    ┌──────────────┐
│ Browser  │────────────▶│  API Gateway │───────────▶│ Order Service│
└──────────┘             └──────────────┘            └──────┬───────┘
                                                           │
                                                    publishes event
                                                           │
                                                           ▼
                                                    ┌─────────────┐
                                                    │    Kafka     │
                                                    └──────┬──────┘
                                          ┌────────────────┼────────────────┐
                                          ▼                ▼                ▼
                                   ┌────────────┐  ┌────────────┐  ┌────────────┐
                                   │ Inventory  │  │ Notification│  │ Analytics  │
                                   │  Service   │  │  Service    │  │  Service   │
                                   └────────────┘  └────────────┘  └────────────┘
</code></pre>
<ul>
<li><p><strong>REST</strong> at the edge: the browser talks to the API gateway using standard HTTP. Cacheable, debuggable, universally supported.</p>
</li>
<li><p><strong>gRPC</strong> between the gateway and internal services: low latency, strong typing, efficient serialization.</p>
</li>
<li><p><strong>Event-driven</strong> for downstream reactions: the order service publishes an event, and multiple consumers react independently.</p>
</li>
</ul>
<h3 id="heading-the-anti-synchronous-trap">The Anti-Synchronous Trap</h3>
<p>A common mistake is using synchronous calls (REST or gRPC) where events are a better fit. The symptom: a service that makes five synchronous calls during a single request, waiting for each to complete before responding to the caller.</p>
<pre><code class="language-typescript">// Anti-pattern: synchronous fan-out
async function confirmOrder(order: Order): Promise&lt;void&gt; {
  await inventoryService.decrementStock(order.items);    // 50ms
  await paymentService.capturePayment(order.paymentId);  // 200ms
  await notificationService.sendConfirmation(order);     // 100ms
  await analyticsService.recordConversion(order);        // 80ms
  await shippingService.createShipment(order);           // 150ms
  // Total: 580ms, and if any one fails, the order fails
}
</code></pre>
<p>Only the first two calls (inventory and payment) are critical to confirming the order. The rest are reactions that can happen asynchronously:</p>
<pre><code class="language-typescript">// Better: synchronous for critical path, events for reactions
async function confirmOrder(order: Order): Promise&lt;void&gt; {
  // Critical path: must succeed for the order to be valid
  await inventoryService.decrementStock(order.items);
  await paymentService.capturePayment(order.paymentId);

  // Non-critical: publish event, let consumers handle the rest
  await publishOrderConfirmed(order);
  // Total: 250ms, and notification/analytics/shipping failures
  // don't block the checkout
}
</code></pre>
<p>This is the same tiered approach from my <a href="https://abisoye.dev/blog/designing-resilient-apis">designing resilient APIs</a> article. Critical operations are synchronous. Non-critical reactions are event-driven. The caller responds faster, and downstream failures do not cascade.</p>
<h2 id="heading-schema-governance-at-scale">Schema Governance at Scale</h2>
<p>As your service count grows, schema management becomes a first-class concern. Here's a practical approach for each pattern.</p>
<h3 id="heading-rest-openapi-as-the-contract">REST: OpenAPI as the Contract</h3>
<pre><code class="language-yaml"># openapi/inventory-service.yaml
openapi: "3.1.0"
info:
  title: Inventory Service
  version: "1.2.0"
paths:
  /api/v1/products/{productId}/stock:
    get:
      operationId: getStock
      parameters:
        - name: productId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Stock level for the product
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StockResponse"
components:
  schemas:
    StockResponse:
      type: object
      required: [productId, available, reserved]
      properties:
        productId:
          type: string
        available:
          type: integer
        reserved:
          type: integer
</code></pre>
<p>Generate client SDKs from the OpenAPI spec using tools like <code>openapi-typescript</code> or <code>openapi-generator</code>. This gives you type safety without the build-time coupling of gRPC.</p>
<h3 id="heading-grpc-proto-registry">gRPC: Proto Registry</h3>
<p>Store <code>.proto</code> files in a shared repository or a dedicated proto registry (Buf Schema Registry is a good option). Use Buf's breaking change detection in CI:</p>
<pre><code class="language-bash"># Detects breaking changes before they merge
buf breaking --against ".git#branch=main"
</code></pre>
<p>This command requires a <code>buf.yaml</code> configuration file at the root of your proto directory. The file defines your module name and any lint or breaking change rules. See the <a href="https://buf.build/docs/configuration/v2/buf-yaml">Buf documentation</a> for setup details.</p>
<p>This fails your pull request if you rename a field, change a type, or reuse a field number. Non-breaking changes (adding fields, adding services) pass through.</p>
<h3 id="heading-events-schema-registry-with-compatibility-modes">Events: Schema Registry with Compatibility Modes</h3>
<p>For event-driven systems, a schema registry enforces compatibility at publish time. Confluent Schema Registry supports four modes:</p>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Rule</th>
<th>Use Case</th>
</tr>
</thead>
<tbody><tr>
<td><strong>BACKWARD</strong></td>
<td>New schema can read old data</td>
<td>Consumer-first evolution</td>
</tr>
<tr>
<td><strong>FORWARD</strong></td>
<td>Old schema can read new data</td>
<td>Producer-first evolution</td>
</tr>
<tr>
<td><strong>FULL</strong></td>
<td>Both directions</td>
<td>Safest, most restrictive</td>
</tr>
<tr>
<td><strong>NONE</strong></td>
<td>No checks</td>
<td>Development only</td>
</tr>
</tbody></table>
<p>Use <code>FULL</code> compatibility for production topics. It ensures that any consumer, regardless of which schema version it was built against, can read any event on the topic.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned the core mechanics of REST, gRPC, and event-driven messaging, the five trade-off dimensions that matter when choosing between them (latency, coupling, schema evolution, debugging, and operational complexity), and a decision framework for matching patterns to specific service interactions.</p>
<p>The key takeaways:</p>
<ol>
<li><p><strong>REST for the edge:</strong> Browser clients, public APIs, simple CRUD. Cacheable, debuggable, universally supported.</p>
</li>
<li><p><strong>gRPC for internal hot paths:</strong> High-throughput service-to-service calls where latency matters and both sides are under your control.</p>
</li>
<li><p><strong>Events for reactions:</strong> When the producer shouldn't wait, when multiple consumers need the same signal, or when temporal decoupling prevents cascading failures.</p>
</li>
<li><p><strong>Use all three:</strong> Most production systems combine patterns. REST at the boundary, gRPC internally, events for async workflows.</p>
</li>
<li><p><strong>Schema governance scales the system:</strong> OpenAPI for REST, proto registries for gRPC, schema registries for events. Without governance, schema changes become the primary source of production incidents.</p>
</li>
</ol>
<p>The right communication pattern isn't a global decision. It's a per-interaction decision, made deliberately, based on which trade-offs you can accept for that specific data flow.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Django REST APIs for Performance: Profiling, Caching, and Scaling. ]]>
                </title>
                <description>
                    <![CDATA[ Performance problems in APIs rarely start as performance problems. They usually start as small design decisions that worked perfectly when the application had ten users, ten records, or a single developer testing locally. Over time, as traffic increa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-optimize-django-rest-apis-for-performance/</link>
                <guid isPermaLink="false">6994b1d13e0696149c7c229c</guid>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ django rest framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Performance Optimization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ scalability ]]>
                    </category>
                
                    <category>
                        <![CDATA[ backend ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mari ]]>
                </dc:creator>
                <pubDate>Tue, 17 Feb 2026 18:22:09 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771352481135/11be538b-aaf5-4c1e-8ee2-99deea5f180e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Performance problems in APIs rarely start as performance problems. They usually start as small design decisions that worked perfectly when the application had ten users, ten records, or a single developer testing locally. Over time, as traffic increases and data grows, those same decisions begin to slow everything down.</p>
<p>In this article, we’ll walk step by step through how performance issues arise in Django REST APIs, how to see them clearly using profiling tools, and how to fix them using query optimization, caching, pagination, and basic scaling strategies.</p>
<p>This article will be most useful for developers who already understand Django, the Django REST Framework, and REST concepts, but are new to performance optimization.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-django-rest-apis-become-slow">Why Django REST APIs Become Slow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-profiling-finding-the-real-bottlenecks">Profiling: Finding the Real Bottlenecks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-logging-sql-queries">Logging SQL Queries</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary-and-next-steps">Summary and Next Steps</a></p>
</li>
</ul>
<h2 id="heading-why-django-rest-apis-become-slow">Why Django REST APIs Become Slow</h2>
<p>Before optimizing anything, it’s important to understand why APIs become slow in the first place.</p>
<p>Most performance issues in Django REST APIs come from three main sources:</p>
<ol>
<li><p>Too many database queries</p>
</li>
<li><p>Doing expensive work repeatedly</p>
</li>
<li><p>Returning more data than necessary</p>
</li>
</ol>
<p>Django is fast by default, but it does exactly what you ask it to do. If your API endpoint triggers 300 database queries, Django will happily run all 300.</p>
<p>Now let’s look at some common causes of performance issues in Django REST APIs.</p>
<h3 id="heading-1-n1-query-problems-in-serializers">1. N+1 Query Problems in Serializers</h3>
<p>This happens when you loop over objects and access related fields, causing a separate query for each object.</p>
<pre><code class="lang-python"><span class="hljs-comment"># models.py</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Author</span>(<span class="hljs-params">models.Model</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">100</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span>(<span class="hljs-params">models.Model</span>):</span>
    title = models.CharField(max_length=<span class="hljs-number">200</span>)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

<span class="hljs-comment"># views.py (naive approach)</span>
posts = Post.objects.all()
<span class="hljs-keyword">for</span> post <span class="hljs-keyword">in</span> posts:
    <span class="hljs-comment"># This triggers a query per post to fetch the author</span>
    print(post.author.name)
</code></pre>
<p>If you have 100 posts, this runs 101 queries: 1 for posts and 100 for authors. Django lazily loads related objects by default, so without intervention, your API performs repetitive database work that slows response times.</p>
<h3 id="heading-2-fetching-related-objects-inefficiently">2. Fetching Related Objects Inefficiently</h3>
<pre><code class="lang-python"><span class="hljs-comment"># Naive queryset fetching all related objects separately</span>
posts = Post.objects.all()
authors = [post.author <span class="hljs-keyword">for</span> post <span class="hljs-keyword">in</span> posts]  <span class="hljs-comment"># triggers extra queries per post</span>
</code></pre>
<p>Each access to <code>post.author</code> triggers a new query. Even though you already fetched all posts, Django lazily loads related objects by default. This creates many extra queries, slowing down your API.</p>
<h3 id="heading-3-serializing-large-datasets-without-pagination">3. Serializing Large Datasets Without Pagination</h3>
<p>Returning large query sets all at once can slow down your API and increase memory usage.</p>
<pre><code class="lang-python"><span class="hljs-comment"># views.py</span>
<span class="hljs-keyword">from</span> rest_framework.response <span class="hljs-keyword">import</span> Response
<span class="hljs-keyword">from</span> rest_framework.decorators <span class="hljs-keyword">import</span> api_view
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Post
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> PostSerializer

<span class="hljs-meta">@api_view(['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">all_posts</span>(<span class="hljs-params">request</span>):</span>
    posts = Post.objects.all()  <span class="hljs-comment"># retrieves all posts at once</span>
    serializer = PostSerializer(posts, many=<span class="hljs-literal">True</span>)
    <span class="hljs-keyword">return</span> Response(serializer.data)
</code></pre>
<p>If your database has thousands of posts, this endpoint fetches everything in memory, serializes it, and sends it over the network. It’s slow and can crash under load. Later, we’ll learn to paginate results efficiently.</p>
<h3 id="heading-4-recomputing-expensive-work-repeatedly">4. Recomputing Expensive Work Repeatedly</h3>
<p>Some endpoints calculate the same values on every request instead of caching or precomputing.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">expensive_view</span>(<span class="hljs-params">request</span>):</span>
    <span class="hljs-comment"># Simulate expensive computation</span>
    result = sum([i**<span class="hljs-number">2</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1000000</span>)])
    <span class="hljs-keyword">return</span> JsonResponse({<span class="hljs-string">"result"</span>: result})
</code></pre>
<p>Even if the data doesn’t change often, this computation happens on every request, consuming CPU time unnecessarily.  </p>
<p>Performance optimization is about reducing unnecessary work.  </p>
<p>At this point, it might be tempting to jump straight into fixes like caching responses or optimizing database queries. But doing that without evidence often leads to wasted effort or even new problems.</p>
<p>Before changing anything, you need to understand where your API is actually spending time. Is it the database? Is it serialization? Is it Python code running repeatedly on every request? This is where profiling becomes essential.</p>
<h2 id="heading-profiling-finding-the-real-bottlenecks">Profiling: Finding the Real Bottlenecks</h2>
<p>Optimizing without profiling is guessing. Profiling helps you answer one question:</p>
<blockquote>
<p>Where is my API actually spending time?</p>
</blockquote>
<p>In practice, profiling means observing an API while it runs and collecting data about what it’s doing. This includes how many database queries are executed, how long those queries take, and how much time is spent in Python code, such as serializers or business logic.</p>
<p>By profiling first, you avoid making assumptions and can focus on fixing the parts of your API that are truly slowing things down.</p>
<h3 id="heading-measuring-query-count-in-a-view">Measuring Query Count in a View</h3>
<p>During development, Django keeps track of all executed queries. You can inspect them directly:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> connection
<span class="hljs-keyword">from</span> rest_framework.decorators <span class="hljs-keyword">import</span> api_view
<span class="hljs-keyword">from</span> rest_framework.response <span class="hljs-keyword">import</span> Response
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Post
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> PostSerializer

<span class="hljs-meta">@api_view(["GET"])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post_list</span>(<span class="hljs-params">request</span>):</span>
    posts = Post.objects.all()
    serializer = PostSerializer(posts, many=<span class="hljs-literal">True</span>)

    response = Response(serializer.data)

    print(<span class="hljs-string">f"Total queries executed: <span class="hljs-subst">{len(connection.queries)}</span>"</span>)

    <span class="hljs-keyword">return</span> response
</code></pre>
<p>If this prints 101 queries for 100 posts, you likely have an N+1 problem. This simple check confirms whether the database layer is the bottleneck.</p>
<p>One of the easiest ways to profile Django applications during development is by using tools that expose this information directly while requests are being processed.</p>
<h3 id="heading-using-the-django-debug-toolbar">Using the Django Debug Toolbar</h3>
<p>The Django Debug Toolbar is one of the simplest ways to understand performance during development. It acts as a lightweight profiling tool that shows what happens behind the scenes when a request is handled.</p>
<p>It shows you:</p>
<ul>
<li><p>How many SQL queries were executed</p>
</li>
<li><p>How long each query took</p>
</li>
<li><p>whether queries are duplicated</p>
</li>
<li><p>Which parts of the request lifecycle are slow</p>
</li>
</ul>
<h4 id="heading-how-to-install-and-enable-the-django-debug-toolbar">How to Install and Enable the Django Debug Toolbar</h4>
<p>First, install it:</p>
<pre><code class="lang-bash">pip install django-debug-toolbar
</code></pre>
<p>In settings.py:</p>
<pre><code class="lang-bash">INSTALLED_APPS = [
    ...
    <span class="hljs-string">"debug_toolbar"</span>,
]

MIDDLEWARE = [
    ...
    <span class="hljs-string">"debug_toolbar.middleware.DebugToolbarMiddleware"</span>,
]

INTERNAL_IPS = [
    <span class="hljs-string">"127.0.0.1"</span>,
]
</code></pre>
<p>In urls.py:</p>
<pre><code class="lang-bash">import debug_toolbar
from django.urls import path, include

urlpatterns = [
    ...
    path(<span class="hljs-string">"__debug__/"</span>, include(debug_toolbar.urls)),
]
</code></pre>
<p>When you load an endpoint in the browser during development, the toolbar displays total SQL queries, execution time, and duplicate queries. This makes inefficiencies immediately visible.</p>
<p>When you load an API endpoint and see 150 SQL queries for a single request, that’s a strong signal that something is wrong, often an N+1 query problem or inefficient serializer behavior.</p>
<h3 id="heading-logging-sql-queries">Logging SQL Queries</h3>
<p>Django allows you to log all executed SQL queries. This is especially useful when debugging API views.</p>
<p>Seeing the raw SQL makes inefficiencies obvious, such as repeated <code>SELECT</code> statements for the same table.</p>
<h4 id="heading-how-to-enable-sql-query-logging">How to Enable SQL Query Logging</h4>
<p>You can configure Django to log all SQL queries in settings.py:</p>
<pre><code class="lang-bash">LOGGING = {
    <span class="hljs-string">"version"</span>: 1,
    <span class="hljs-string">"handlers"</span>: {
        <span class="hljs-string">"console"</span>: {
            <span class="hljs-string">"class"</span>: <span class="hljs-string">"logging.StreamHandler"</span>,
        },
    },
    <span class="hljs-string">"loggers"</span>: {
        <span class="hljs-string">"django.db.backends"</span>: {
            <span class="hljs-string">"handlers"</span>: [<span class="hljs-string">"console"</span>],
            <span class="hljs-string">"level"</span>: <span class="hljs-string">"DEBUG"</span>,
        },
    },
}
</code></pre>
<p>With this configuration, every SQL query will be printed to the console when your API runs. Repeated SELECT statements or unexpected queries become obvious.</p>
<h3 id="heading-profiling-api-response-time">Profiling API Response Time</h3>
<p>Database queries are only one part of API performance. Beyond queries, it’s also important to measure the total response time of an endpoint.</p>
<p>Profiling response time helps you understand whether delays are caused by database access or by other parts of the request lifecycle. For example, if an endpoint takes 1.2 seconds to respond but only 50 milliseconds are spent on database queries, the bottleneck is likely in serialization, business logic, or repeated computations in Python.</p>
<p>By comparing query time and total response time, profiling helps you identify what to fix first instead of optimizing the wrong layer of the system.</p>
<h4 id="heading-how-to-measure-total-response-time">How to Measure Total Response Time</h4>
<pre><code class="lang-bash">import time
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view([<span class="hljs-string">"GET"</span>])
def example_view(request):
    start_time = time.time()

    <span class="hljs-comment"># Simulate work</span>
    data = {<span class="hljs-string">"message"</span>: <span class="hljs-string">"Hello world"</span>}

    response = Response(data)

    end_time = time.time()
    <span class="hljs-built_in">print</span>(f<span class="hljs-string">"Response time: {end_time - start_time:.4f} seconds"</span>)

    <span class="hljs-built_in">return</span> response
</code></pre>
<p>If database queries are fast but the total response time is high, the bottleneck may be serialization or expensive Python logic.  </p>
<p>Once you’ve identified that database access is a significant contributor to slow response times, the next step is to look more closely at how Django retrieves related data.</p>
<h3 id="heading-sql-query-optimization-in-django-rest-apis">SQL Query Optimization in Django REST APIs</h3>
<p>One of the most common reasons Django REST APIs become slow is inefficient access to related objects. This often manifests as the N+1 query problem, where fetching related objects triggers a separate database query for each item. Identifying and fixing this problem can significantly reduce the number of queries and improve API performance.</p>
<h4 id="heading-understanding-the-n1-query-problem">Understanding the N+1 Query Problem</h4>
<p>Consider a simple example:</p>
<ul>
<li><p>You fetch a list of posts</p>
</li>
<li><p>Each post has an author</p>
</li>
<li><p>For every post, Django fetches the author separately</p>
</li>
</ul>
<p>If you have 100 posts, this results in 101 queries: 1 for the posts and 100 for the authors. This happens because Django lazily loads related objects by default. Without intervention, your API performs repetitive database work that slows down response times.</p>
<h4 id="heading-solving-the-problem-with-selectrelated-and-prefetchrelated">Solving the Problem with <code>select_related</code> and <code>prefetch_related</code></h4>
<p>Django provides built-in tools to control how related objects are loaded efficiently: <code>select_related</code> and <code>prefetch_related</code>.</p>
<p><strong>1. Using</strong> <code>select_related</code></p>
<p><code>select_related</code> is designed for foreign key and one-to-one relationships. It performs an SQL join and retrieves related objects in a single query.</p>
<p>Use it when:</p>
<ul>
<li><p>You know you will access related objects</p>
</li>
<li><p>The relationship is one-to-one or many-to-one</p>
</li>
</ul>
<pre><code class="lang-bash">posts = Post.objects.select_related(<span class="hljs-string">"author"</span>)

<span class="hljs-keyword">for</span> post <span class="hljs-keyword">in</span> posts:
    <span class="hljs-built_in">print</span>(post.author.name)  <span class="hljs-comment"># No additional queries</span>
</code></pre>
<p>This performs a SQL JOIN and retrieves posts and authors in a single query, eliminating the N+1 problem.</p>
<p>It reduces multiple queries into just one, avoiding repeated database hits.</p>
<p><strong>2. Using</strong> <code>prefetch_related</code></p>
<p><code>prefetch_related</code> is used for many-to-many and reverse foreign key relationships. It performs separate queries for each related table but combines the results in Python.</p>
<p>Use it when:</p>
<ul>
<li><p>A SQL join would produce too much duplicated data</p>
</li>
<li><p>You are dealing with collections of related objects</p>
</li>
</ul>
<h4 id="heading-example-how-to-optimize-a-many-to-many-relationship">Example: How to Optimize a Many-to-Many Relationship</h4>
<p>Consider a blog application where posts can have multiple tags:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># models.py</span>
class Tag(models.Model):
    name = models.CharField(max_length=50)

class Post(models.Model):
    title = models.CharField(max_length=200)
    tags = models.ManyToManyField(Tag)
</code></pre>
<p>Now imagine fetching posts and accessing their tags:</p>
<pre><code class="lang-bash">posts = Post.objects.all()

<span class="hljs-keyword">for</span> post <span class="hljs-keyword">in</span> posts:
    <span class="hljs-built_in">print</span>(post.tags.all())  <span class="hljs-comment"># Triggers additional queries</span>
</code></pre>
<p>If you have 100 posts, Django may execute:</p>
<ul>
<li><p>1 query to fetch posts</p>
</li>
<li><p>1 query per post to fetch related tags</p>
</li>
</ul>
<p>This results in many unnecessary database hits.</p>
<p>You can optimize this using <code>prefetch_related</code>:</p>
<pre><code class="lang-bash">posts = Post.objects.prefetch_related(<span class="hljs-string">"tags"</span>)

<span class="hljs-keyword">for</span> post <span class="hljs-keyword">in</span> posts:
    <span class="hljs-built_in">print</span>(post.tags.all())  <span class="hljs-comment"># Uses prefetched data</span>
</code></pre>
<p>With this approach, Django performs one query for posts and one query for all related tags. It then matches them in Python, eliminating repeated database queries.</p>
<p>Together, these tools allow you to optimize your queries and eliminate the N+1 problem efficiently.</p>
<h4 id="heading-common-beginner-mistakes">Common Beginner Mistakes</h4>
<p>Even after applying these optimizations, it’s easy to make mistakes. Watch out for:</p>
<ul>
<li><p>Forgetting that serializers can trigger additional queries</p>
</li>
<li><p>Using <code>select_related</code> on many-to-many relationships</p>
</li>
<li><p>Assuming Django automatically optimizes queries</p>
</li>
<li><p>Not checking the query count after adding serializers</p>
</li>
</ul>
<p>Paying attention to these pitfalls ensures your API remains fast and scalable.</p>
<h3 id="heading-caching-in-django-rest-apis">Caching in Django REST APIs</h3>
<p>Even after optimizing database queries, API performance can still suffer if the same computations or database lookups are performed repeatedly. This is where caching comes in. Caching is a technique for storing the results of expensive operations so they can be retrieved more quickly the next time they are needed.</p>
<p>At its core, caching exists because computers have multiple layers of memory with different speeds:</p>
<ul>
<li><p>CPU registers (fastest)</p>
</li>
<li><p>L1, L2, L3 caches</p>
</li>
<li><p>Main memory (RAM)</p>
</li>
<li><p>SSD storage</p>
</li>
<li><p>HDD storage (slowest)</p>
</li>
</ul>
<p>Each layer trades speed for size: the closer the data is to the CPU, the faster it can be accessed. Software systems use the same principle; by storing frequently accessed data in a “closer” or faster location, applications can respond more quickly.</p>
<h4 id="heading-cache-eviction">Cache Eviction</h4>
<p>Caches are limited in size, so when a cache is full, some data must be removed to make room for new data. This process is called cache eviction.</p>
<p>Common eviction strategies include:</p>
<ul>
<li><p><strong>Least Recently Used (LRU):</strong> removes the data that hasn’t been accessed for the longest time</p>
</li>
<li><p><strong>Random Replacement:</strong> removes a random item from the cache</p>
</li>
</ul>
<p>The goal is to keep the data that is most likely to be requested again while freeing space for new data. Understanding this helps developers use caching effectively.</p>
<h4 id="heading-caching-in-application-architectures">Caching in Application Architectures</h4>
<p>Caching exists at several levels in modern software systems:</p>
<ul>
<li><p><strong>Client-side caching:</strong> Web browsers cache HTTP responses to reduce the need for repeated network requests. This is controlled with HTTP headers like <code>Cache-Control</code>.</p>
</li>
<li><p><strong>CDN caching:</strong> Content Delivery Networks store static assets closer to users, reducing latency and server load.</p>
</li>
<li><p><strong>Backend caching:</strong> Backend services cache results from database queries, computed values, or API responses. This is where Django caching is most commonly applied.</p>
</li>
</ul>
<p>By applying caching strategically at the backend, APIs can serve data faster while reducing computation and database load.</p>
<h4 id="heading-caching-in-django">Caching in Django</h4>
<p>Django provides a flexible caching framework that supports multiple backends, including in-memory, file-based, database-backed, and third-party stores like Redis. The main types of caching in Django are:</p>
<ol>
<li><p><strong>Per-view caching:</strong> caches the entire output of a view. Ideal for endpoints where responses rarely change.</p>
<pre><code class="lang-python"> <span class="hljs-keyword">from</span> django.views.decorators.cache <span class="hljs-keyword">import</span> cache_page

<span class="hljs-meta"> @cache_page(60 * 15)  # cache for 15 minutes</span>
 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">my_view</span>(<span class="hljs-params">request</span>):</span>
</code></pre>
<ol start="2">
<li><p>Template fragment caching: caches specific parts of a template to avoid repeated rendering.</p>
</li>
<li><p>Low-level caching: gives full control over what is cached and for how long, making it ideal for API responses.</p>
</li>
</ol>
</li>
</ol>
<p>    By combining these approaches, you can reduce repeated work in your API, lower database load, and speed up response times.</p>
<h3 id="heading-when-to-use-redis">When to Use Redis</h3>
<p>While Django’s built-in caching backends are sufficient for many projects, high-traffic APIs often require a shared, in-memory cache. This is where Redis excels. Redis is designed for fast access, low latency, and can handle frequent reads across multiple servers.</p>
<p>You should consider using Redis when:</p>
<ul>
<li><p>Data is read frequently but changes infrequently</p>
</li>
<li><p>Low latency is important for API responses</p>
</li>
<li><p>You need cache expiration and eviction policies</p>
</li>
<li><p>You want a shared cache across multiple servers or services</p>
</li>
</ul>
<p>Redis is particularly effective for API endpoints that serve the same data to many users, such as frequently accessed lists or computed results.</p>
<h3 id="heading-common-beginner-mistakes-1">Common Beginner Mistakes</h3>
<p>Caching is powerful, but it’s easy to misuse. Some common pitfalls include:</p>
<ul>
<li><p><strong>Caching everything blindly:</strong> not all data benefits from caching</p>
</li>
<li><p><strong>Forgetting cache invalidation:</strong> stale data can lead to incorrect responses</p>
</li>
<li><p><strong>Using cache where query optimization would suffice:</strong> sometimes optimizing database queries is a better solution than caching.</p>
</li>
</ul>
<p>Remember: caching should complement good database design, not replace it.</p>
<h3 id="heading-pagination-and-limiting-expensive-datasets">Pagination and Limiting Expensive Datasets</h3>
<p>Even with caching, returning large datasets in a single request can slow down your API and increase memory usage. Pagination is a simple and effective way to limit the amount of data returned at once.</p>
<p>Pagination helps by reducing:</p>
<ul>
<li><p>Database load</p>
</li>
<li><p>Memory usage</p>
</li>
<li><p>Serialization time</p>
</li>
<li><p>Network transfer size</p>
</li>
</ul>
<p>Django REST Framework provides built-in pagination classes that make it easy to paginate endpoints. As a rule of thumb, always paginate list endpoints unless there is a strong reason not to.</p>
<h3 id="heading-load-testing-and-measuring-improvement">Load Testing and Measuring Improvement</h3>
<p>Optimizations are only meaningful if you can measure their impact. Load testing simulates multiple users accessing your API simultaneously, helping you answer key questions:</p>
<ul>
<li><p>How many requests per second can my API handle?</p>
</li>
<li><p>Where does the API start to break under load?</p>
</li>
<li><p>Did caching, query optimization, and pagination actually improve performance?</p>
</li>
</ul>
<p>By running load tests before and after optimization, you can validate that your changes have the desired effect and avoid optimizing the wrong parts of your system.</p>
<h2 id="heading-summary-and-next-steps">Summary and Next Steps</h2>
<p>Optimizing Django REST APIs isn’t about chasing every tiny micro-optimization. It’s about reducing unnecessary work and focusing on the parts of your API that actually slow down performance.</p>
<h4 id="heading-key-takeaways">Key Takeaways</h4>
<ul>
<li><p><strong>Profile before optimizing:</strong> Identify the real bottlenecks before making changes.</p>
</li>
<li><p><strong>Reduce database queries:</strong> Use techniques like <code>select_related</code>, <code>prefetch_related</code>, and avoid N+1 queries.</p>
</li>
<li><p><strong>Cache frequently accessed data:</strong> Use Django caching and Redis to reduce repeated computations.</p>
</li>
<li><p><strong>Paginate large datasets:</strong> Limit memory usage and network load by returning data in chunks.</p>
</li>
<li><p><strong>Measure performance changes:</strong> Always verify that your optimizations have a real impact.</p>
</li>
</ul>
<h4 id="heading-next-steps-for-your-apis">Next Steps for Your APIs</h4>
<ol>
<li><p><strong>Add profiling to your existing APIs</strong> to understand where time is spent.</p>
</li>
<li><p><strong>Identify one slow endpoint</strong> and focus on optimizing it first.</p>
</li>
<li><p><strong>Optimize database queries</strong> using Django ORM best practices.</p>
</li>
<li><p><strong>Introduce caching carefully</strong>; avoid caching everything blindly.</p>
</li>
<li><p><strong>Measure the results</strong> with load testing and performance metrics.</p>
</li>
</ol>
<p>Remember: Performance optimization is not a one-time task. It’s a habit built by continuously observing how your system works, testing improvements, and applying changes where they make the most impact.</p>
<h2 id="heading-read-more">Read More</h2>
<ol>
<li><p><a target="_blank" href="https://www.django-rest-framework.org/topics/performance/">DRF Performance</a></p>
</li>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/stable/topics/db/optimization/">Django ORM Optimization</a></p>
</li>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/stable/topics/db/optimization/#select-related">Understanding N+1 queries</a></p>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Web Services Work – The Unseen Engines of the Connected World ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wondered how your weather app instantly knows the forecast, how you can book flights from multiple airlines on one travel site, or how logging into one service can magically log you into another? The answer often lies in a powerful, yet... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-web-services-work-with-examples/</link>
                <guid isPermaLink="false">6824ad336ea9fe84cfb4d0c4</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SOAP API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kumar Anand ]]>
                </dc:creator>
                <pubDate>Wed, 14 May 2025 14:48:19 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747156692079/512460b1-28dc-4769-95d4-2c842a316a51.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wondered how your weather app instantly knows the forecast, how you can book flights from multiple airlines on one travel site, or how logging into one service can magically log you into another?</p>
<p>The answer often lies in a powerful, yet often invisible, technology: <strong>Web Services</strong>.</p>
<p>Think of the internet as a bustling city. Different buildings (applications) have different functions and are built by different architects (developers) using different materials (programming languages and platforms).</p>
<p>So how do these distinct buildings interact efficiently? They need standardized roads, delivery services, and communication protocols. Web services are the digital equivalent of these crucial city infrastructure components.</p>
<p>In this article, you’ll learn what Web Services are and why they’re important. You’ll also learn about different types of Web Services, like Simple Object Access Protocol (SOAP) and Representational State Transfer (REST), and when to use each one. We’ll wrap up with some examples so you can see them in action.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-exactly-is-a-web-service">What Exactly is a Web Service?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-are-web-services-so-important">Why are Web Services So Important?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-web-services">Types of Web Services</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-comparing-and-contrasting-soap-and-rest-web-services">Comparing and Contrasting SOAP and REST Web Services</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-if-one-service-uses-soap-and-the-other-uses-rest">What if one service uses SOAP and the other uses REST?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-web-services-in-action-examples">Web Services in Action: Examples</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts:</a></p>
</li>
</ul>
<h2 id="heading-what-exactly-is-a-web-service">What Exactly is a Web Service?</h2>
<p>At its core, a web service is a standardized way for different software applications to communicate with each other over a network – typically the internet. It allows application 'A' (running on, say, a Windows server using Java) to request information or trigger an action from application 'B' (running on a Linux machine using Python), without either application needing to know the intricate internal details of the other.</p>
<p>Here’s how they make this happen:</p>
<ol>
<li><p><strong>Network accessibility:</strong> They operate over standard web protocols like HTTP/HTTPS.</p>
</li>
<li><p><strong>Standardized messaging:</strong> They use common data formats like XML (Extensible Markup Language) or JSON (JavaScript Object Notation) to structure the data being exchanged.</p>
</li>
<li><p><strong>Interface description:</strong> They often come with a "contract" or description (like WSDL for SOAP services or OpenAPI/Swagger definitions for REST APIs) that tells other applications <em>how</em> to interact with them – what functions are available and what data format to expect.</p>
</li>
</ol>
<h2 id="heading-why-are-web-services-so-important">Why are Web Services So Important?</h2>
<p>The rise of web services has revolutionized software development and the internet itself. They’re important for several key reasons.</p>
<p>First, <strong>interoperability.</strong> This is the biggest win. Web services break down technology silos. An application written in C# can seamlessly talk to one written in Ruby, as long as they agree on the web service protocol and data format.</p>
<p>Next, <strong>reusability.</strong> A company can build a specific function (like processing payments or checking stock inventory) as a web service once. Then, multiple internal or external applications can reuse that same service, saving significant development time and effort.</p>
<p>Also, <strong>loose coupling.</strong> Applications using a web service don't need to be tightly bound to it. The service provider can update the internal workings of the service without breaking the applications that consume it, as long as the communication interface remains consistent. This makes systems more flexible and easier to maintain.</p>
<p>And finally, <strong>platform independence.</strong> Because they rely on web standards, web services work across different operating systems and hardware.</p>
<h2 id="heading-types-of-web-services">Types of Web Services</h2>
<p>Web services can be broadly categorized into different types, each with its own characteristics and suitable use cases. The two most prominent types are SOAP and REST. Other types include XML-RPC, UDDI, GraphQL , and gRPC.</p>
<h3 id="heading-soap-simple-object-access-protocol"><strong>SOAP (Simple Object Access Protocol)</strong></h3>
<p>SOAP web services are often used in enterprise-level applications requiring high security and transactional integrity, like banking, finance, and telecommunications.</p>
<ul>
<li><p><strong>Protocol:</strong> SOAP (Simple Object Access Protocol) is a formal protocol with strict rules defined by the W3C that relies on XML for message format and usually HTTP/HTTPS for message negotiation and transmission.</p>
</li>
<li><p><strong>Structure:</strong> SOAP messages are composed of an envelope, header, and body:</p>
<ul>
<li><p><strong>Envelope:</strong> Defines the start and end of the message, and includes namespaces for components.</p>
</li>
<li><p><strong>Header:</strong> Contains optional attributes for message routing and quality of service.</p>
</li>
<li><p><strong>Body:</strong> Contains the actual call and response information, wrapped in XML.</p>
</li>
</ul>
</li>
<li><p><strong>Communication:</strong> SOAP is protocol-driven and uses WSDL (Web Services Description Language) to describe the services offered and how to interact with them.</p>
</li>
<li><p><strong>Use cases:</strong> A SOAP request might be used to call a banking service to check an account balance. The response will be strictly formatted as XML, fulfilling the service’s requirements.</p>
</li>
</ul>
<h4 id="heading-example-a-currency-conversion-web-service">Example: a currency conversion web service</h4>
<p>SOAP Request (XML)</p>
<pre><code class="lang-xml">POST /CurrencyService.asmx HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.example.com/ConvertCurrency"

<span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">soap:Envelope</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
               <span class="hljs-attr">xmlns:xsd</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema"</span>
               <span class="hljs-attr">xmlns:soap</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/envelope/"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">soap:Body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ConvertCurrency</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.example.com/"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">FromCurrency</span>&gt;</span>USD<span class="hljs-tag">&lt;/<span class="hljs-name">FromCurrency</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ToCurrency</span>&gt;</span>EUR<span class="hljs-tag">&lt;/<span class="hljs-name">ToCurrency</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Amount</span>&gt;</span>100<span class="hljs-tag">&lt;/<span class="hljs-name">Amount</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ConvertCurrency</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">soap:Body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">soap:Envelope</span>&gt;</span>
</code></pre>
<p>SOAP Response (XML)</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">soap:Envelope</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
               <span class="hljs-attr">xmlns:xsd</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema"</span>
               <span class="hljs-attr">xmlns:soap</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/envelope/"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">soap:Body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ConvertCurrencyResponse</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.example.com/"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ConvertCurrencyResult</span>&gt;</span>92.5<span class="hljs-tag">&lt;/<span class="hljs-name">ConvertCurrencyResult</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ConvertCurrencyResponse</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">soap:Body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">soap:Envelope</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746789572894/08bb3d28-2552-4791-a8fd-6f560a1a5dc0.png" alt="SOAP Architecture" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-rest-representational-state-transfer"><strong>REST (Representational State Transfer)</strong></h3>
<p>REST web services are often used for building APIs that let apps perform CRUD operations on resources, like fetching data from a database or interacting with other services. REST is especially popular in web development because it’s relatively simplicity, quite scalable, and uses standard HTTP methods (GET, POST, PUT, DELETE).</p>
<ul>
<li><p><strong>Architecture:</strong> REST (Representational State Transfer) is an architectural style rather than a protocol. It relies on standard HTTP methods like GET, POST, PUT, DELETE, to interact with resources.</p>
</li>
<li><p><strong>Data Exchange:</strong> REST usually exchanges data in JSON or XML format. JSON is more common due to its lightweight nature.</p>
</li>
<li><p><strong>Structure:</strong> REST doesn’t have a WSDL-like formal contract. Instead, resources are identified via URLs, and HTTP status codes indicate the result of requests.</p>
</li>
<li><p>Generally considered simpler, more flexible, and scalable, making it extremely popular for web and mobile applications (these are often referred to as RESTful APIs).</p>
</li>
<li><p><strong>Use cases:</strong> A REST API might be used to retrieve data about a book in a bookstore application, using a simple HTTP GET request.</p>
</li>
</ul>
<h4 id="heading-example-a-currency-conversion-web-service-1">Example: a currency conversion web service</h4>
<p>REST Request</p>
<pre><code class="lang-http"><span class="hljs-keyword">GET</span> <span class="hljs-string">/api/convert?from=USD&amp;to=EUR&amp;amount=100</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: www.example.com
</code></pre>
<p>OR</p>
<p>Using <code>POST</code>:</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/api/convert</span> HTTP/1.1
<span class="hljs-attribute">Host</span>: www.example.com
<span class="hljs-attribute">Content-Type</span>: application/json

<span class="json">{
  <span class="hljs-attr">"from"</span>: <span class="hljs-string">"USD"</span>,
  <span class="hljs-attr">"to"</span>: <span class="hljs-string">"EUR"</span>,
  <span class="hljs-attr">"amount"</span>: <span class="hljs-number">100</span>
}</span>
</code></pre>
<p>REST Response (JSON)</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"from"</span>: <span class="hljs-string">"USD"</span>,
  <span class="hljs-attr">"to"</span>: <span class="hljs-string">"EUR"</span>,
  <span class="hljs-attr">"amount"</span>: <span class="hljs-number">100</span>,
  <span class="hljs-attr">"result"</span>: <span class="hljs-number">92.5</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746789618280/9b887c38-e350-4bda-8b4a-99437df9c90f.png" alt="REST Architecture" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In modern web development, particularly for public APIs and microservices, REST (especially using JSON over HTTPS) has become the most popular and often preferred approach due to its simplicity and performance benefits. But SOAP remains relevant and necessary in specific enterprise contexts.</p>
<h2 id="heading-comparing-and-contrasting-soap-and-rest-web-services">Comparing and Contrasting SOAP and REST Web Services</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>SOAP</strong></td><td><strong>REST</strong></td></tr>
</thead>
<tbody>
<tr>
<td><em>Type</em></td><td>Protocol</td><td>Architectural Style</td></tr>
<tr>
<td><em>Standards</em></td><td>Strictly defined, relies on standards like WS-Security</td><td>Loosely defined, follows HTTP standards</td></tr>
<tr>
<td><em>Data Format</em></td><td>Primarily XML</td><td>Supports various formats (JSON, XML, HTML, plain text), JSON is common</td></tr>
<tr>
<td><em>Bandwidth/Resource</em></td><td>More required due to verbose XML</td><td>Less required, lightweight</td></tr>
<tr>
<td><em>Security</em></td><td>Built-in security features (WS-Security), support encryption</td><td>Inherits security from underlying transport (HTTPS), additional mechanisms like OAuth can be used</td></tr>
<tr>
<td><em>Business Logic</em></td><td>Exposed through service interfaces</td><td>Exposed through URIs representing resources</td></tr>
<tr>
<td><em>Ease of Use</em></td><td>Can be complex, requires specific tools, steeper learning curve</td><td>Generally easier to build and consume, shorter learning curve</td></tr>
<tr>
<td><em>Performance</em></td><td>Can be slower due to XML parsing overhead</td><td>Faster performance, especially with JSON and caching</td></tr>
<tr>
<td><em>Scalability</em></td><td>Can be challenging to scale due to state management (if used)</td><td>Easier to scale due to stateless nature</td></tr>
<tr>
<td><em>Transport</em></td><td>Transport independent (HTTP, SMTP, TCP, JMS)</td><td>Primarily uses HTTP</td></tr>
<tr>
<td><em>Error Handling</em></td><td>Built-in error handling with standardized fault codes</td><td>Relies on HTTP status codes and sometimes custom error responses</td></tr>
<tr>
<td><em>Caching</em></td><td>SOAP calls are generally not cacheable (especially with POST)</td><td>REST responses can be cached</td></tr>
<tr>
<td><em>Statefulness</em></td><td>Supports both stateful and stateless operations</td><td>Primarily stateless</td></tr>
<tr>
<td><em>Tooling</em></td><td>Requires specific SOAP toolkits for development and consumption</td><td>Can be implemented with standard HTTP libraries and tools</td></tr>
<tr>
<td><em>Documentation</em></td><td>Uses WSDL for service description</td><td>Documentation often relies on OpenAPI Specification (Swagger) or similar tools</td></tr>
<tr>
<td><em>Use Cases</em></td><td>Enterprise applications, complex transactions, high security requirements, asynchronous operations, stateful operations (if needed)</td><td>Web applications, mobile apps, public APIs, simple and scalable services, scenarios with limited bandwidth</td></tr>
</tbody>
</table>
</div><h2 id="heading-what-if-one-service-uses-soap-and-the-other-uses-rest">What if One Service Uses SOAP and the Other Uses REST?</h2>
<p>By default, SOAP and REST are not directly compatible because SOAP uses XML with a strict message format, and REST uses HTTP methods and often JSON payloads.</p>
<p>So, they can’t communicate to each other directly without some integration layer or adapter. Here’s how you can handle this situation:</p>
<ul>
<li><p><strong>Use intermediary services:</strong> You can use a middleware or API gateway that can handle both SOAP and REST protocols. These services can translate SOAP requests into REST requests and vice-versa.</p>
</li>
<li><p><strong>Use adapters:</strong> Write adapters that convert SOAP XML messages to REST JSON requests. Essentially, a piece of software acts as a translator between the two formats.</p>
</li>
<li><p><strong>Direct integration:</strong> While complex, this involves custom software development where the SOAP service can be manually configured to invoke REST endpoints.</p>
</li>
<li><p><strong>Use an ESB (Enterprise Service Bus):</strong> An ESB can integrate diverse applications and data formats within enterprise architecture, acting as a mediator that understands both SOAP and REST.</p>
</li>
<li><p><strong>Expose a hybrid API:</strong> Some modern APIs expose both SOAP and REST endpoints for the same backend logic.</p>
<ul>
<li>Example: Amazon Web Services (AWS) used to have SOAP and REST APIs for some services. This lets clients choose which protocol they prefer.</li>
</ul>
</li>
</ul>
<h2 id="heading-web-services-in-action-examples">Web Services in Action: Examples</h2>
<ul>
<li><p><strong>Weather apps:</strong> Your phone app likely calls a weather web service, sending your location and receiving back forecast data.</p>
</li>
<li><p><strong>Online payments:</strong> When you buy something online, the e-commerce site often communicates with a payment gateway's web service to securely process your credit card information.</p>
</li>
<li><p><strong>Travel aggregators:</strong> Sites like MakeMyTrip or Kayak use web services provided by airlines and hotels to fetch real-time flight and room availability and prices.</p>
</li>
<li><p><strong>Social logins:</strong> "Login with Google" or "Login with Facebook" buttons use authentication web services (often based on OAuth) to verify your identity without you needing a separate password for that site.</p>
</li>
</ul>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Web services have fundamentally transformed how applications interact and exchange data over networks. Their ability to facilitate interoperability, reusability, and scalability has made them indispensable in modern software development and system integration.</p>
<p>While SOAP and REST represent the two dominant styles, each with its strengths and weaknesses, their choice often depends on specific project requirements, particularly concerning security, performance, and complexity.</p>
<p>Understanding the core functionalities, underlying technologies, common use cases, and security considerations of web services provides a solid foundation for navigating the landscape of distributed computing.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn REST API Principles by Building an Express App ]]>
                </title>
                <description>
                    <![CDATA[ Web development revolves around communication – communication between browsers and servers, as well as frontend applications and backends. At the centre of this is the API. And the REST architecture has become a popular way to design APIs that are cl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-rest-api-principles-by-building-an-express-app/</link>
                <guid isPermaLink="false">68066255e4a48bef99b3c63e</guid>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ikegah Oliver ]]>
                </dc:creator>
                <pubDate>Mon, 21 Apr 2025 15:20:53 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745003938509/442fd99e-d098-4a5a-98d7-94c4af9a5d55.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Web development revolves around communication – communication between browsers and servers, as well as frontend applications and backends. At the centre of this is the API. And the REST architecture has become a popular way to design APIs that are clean, consistent, and easy to use in web development.</p>
<p>REST works so well because it speaks the web’s native language. It uses familiar HTTP methods like <code>GET</code>, <code>POST</code>, <code>PUT</code>, and <code>DELETE</code>, treats data as resources, and follows clear conventions. All this makes it easy to understand, quick to implement, and widely supported, which is why most modern web APIs follow REST principles.</p>
<p>In this article, I will explore REST concepts and core principles while we build a simple Express application step by step. You will learn:</p>
<ul>
<li><p>What is REST architecture, and what are its advantages in web development?</p>
</li>
<li><p>The core REST principles (statelessness, resources, HTTP methods, and so on)</p>
</li>
<li><p>How to implement these principles in a real Express.js app</p>
</li>
<li><p>Best practices for designing clean and consistent APIs</p>
</li>
</ul>
<h3 id="heading-heres-what-we-will-cover">Here’s what we will cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-rest">What is REST</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-use-rest">Why use REST?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-principles-of-rest-architecture">Core Principles of REST Architecture</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-a-simple-express-app">Build a Simple Express App</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-express">What is Express?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-set-up-the-express-app">Set Up the Express App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-restful-resources">Build RESTful Resources</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-middlewares">Middlewares</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-test-your-express-app">Test your Express App</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-bad-rest-practices-to-avoid">Bad REST Practices to Avoid</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-rest">What is REST?</h2>
<p>Representational State Transfer (REST) is a style of designing networked applications that emphasises a stateless client-server communication model centred around resources. Think of it like ordering at a restaurant: each time you ask for something, you have to tell the waiter exactly what you want, and they don't remember your previous orders.</p>
<p>RESTful APIs treat data as resources, each accessible through a unique web address (URI). Then, it leverages the standard actions defined by HTTP methods – POST to create new resources, GET to retrieve them, PUT to modify existing ones, and DELETE to remove them – providing a consistent and well-understood way to interact with data over the internet.</p>
<h2 id="heading-why-use-rest">Why Use REST?</h2>
<p>REST architectural principles offer a compelling set of advantages that contribute to building robust, scalable, and maintainable web services. Below are some of the key benefits that make REST a preferred choice for modern web development:</p>
<ul>
<li><p><strong>Simplicity and familiarity:</strong> REST leverages standard HTTP, which is already well-understood by developers and infrastructure.</p>
</li>
<li><p><strong>Scalability:</strong> The stateless nature of REST allows for easy scaling of both client and server components independently.</p>
</li>
<li><p><strong>Flexibility and interoperability:</strong> RESTful APIs can be consumed by a wide variety of clients, regardless of the technology stack.</p>
</li>
<li><p><strong>Cacheability:</strong> REST's design supports caching mechanisms, leading to improved performance and reduced server load.</p>
</li>
<li><p><strong>Loose coupling:</strong> The client and server are independent, allowing for changes on either side without necessarily affecting the other.</p>
</li>
<li><p><strong>Visibility and monitoring:</strong> The straightforward nature of HTTP requests and responses makes it easier to monitor and debug interactions.</p>
</li>
</ul>
<h2 id="heading-core-principles-of-rest-architecture">Core Principles of REST Architecture</h2>
<p>REST (Representational State Transfer) is built on a few simple principles that make APIs easy to understand and use. Here’s a quick breakdown of the key ones:</p>
<h3 id="heading-statelesness">Statelesness</h3>
<p>Every request from the client to the server must contain all the information needed to process it. The server doesn’t store anything about the client between requests – no session, no memory of previous actions.</p>
<p><strong>Example:</strong> If a user sends <code>GET /movies/1</code>, the server returns the movie data without needing to know whether the user is logged in or what they requested before.</p>
<p>This makes APIs easier to scale, since each request can be handled independently.</p>
<h3 id="heading-resource-and-uris">Resource and URIs</h3>
<p>In REST, everything you work with is considered a resource – users, products, and so on. Each resource should be accessible via a unique, meaningful URL.</p>
<p><strong>Example:</strong></p>
<ul>
<li><p><code>/movies</code> – a collection of movie resources</p>
</li>
<li><p><code>/movies/42</code> – a specific movie with ID 42</p>
</li>
</ul>
<p>Resources are treated like nouns. Actions are determined by the HTTP method used.</p>
<h3 id="heading-standard-http-methods">Standard HTTP Methods</h3>
<p>REST takes full advantage of HTTP methods to describe what action you’re taking on a resource:</p>
<ul>
<li><p><code>GET</code> – retrieve data</p>
</li>
<li><p><code>POST</code> – create a new resource</p>
</li>
<li><p><code>PUT</code> – update or replace a resource</p>
</li>
<li><p><code>PATCH</code> – partially update a resource</p>
</li>
<li><p><code>DELETE</code> – remove a resource</p>
</li>
</ul>
<p><strong>Example:</strong> To delete a movie, you’d send a <code>DELETE</code> request to <code>/movies/42</code>. That’s clear, consistent, and intuitive.</p>
<h3 id="heading-uniform-interface">Uniform Interface</h3>
<p>REST enforces a consistent structure for communication between client and server. This means all REST APIs should behave similarly, no matter who built them. It includes:</p>
<ul>
<li><p>Using URIs to identify resources</p>
</li>
<li><p>Using standard HTTP methods</p>
</li>
<li><p>Representing data in formats like JSON or XML</p>
</li>
<li><p>Self-descriptive messages (for example, proper status codes and headers)</p>
</li>
</ul>
<p>This consistency makes it easier for developers to understand and integrate with RESTful APIs.</p>
<h3 id="heading-cacheability">Cacheability</h3>
<p>Servers should label responses as cacheable (stored to be retrieved later) or not, so clients can reuse responses when appropriate. This reduces unnecessary server load and improves performance.</p>
<p><strong>Example:</strong> A <code>GET /movies</code> response can be cached for 5 minutes if the data doesn’t change frequently. That means fewer repeated calls for the same info.</p>
<h3 id="heading-client-server-separation">Client-Server Separation</h3>
<p>The client (frontend) and server (backend) operate independently. The client just needs to know how to communicate with the API – it doesn’t care how the server handles data, and vice versa.</p>
<p>This separation allows teams to develop and scale frontend and backend systems separately.</p>
<p>The principles above help create APIs that are scalable, predictable, and easy to work with.</p>
<h2 id="heading-how-to-build-a-simple-express-app">How to Build a Simple Express App</h2>
<h3 id="heading-what-is-express">What is Express?</h3>
<p>Express.js is a lightweight and flexible Node.js web application framework. Built on top of Node.js, it provides a robust set of features for building single-page, multi-page, and hybrid web applications and APIs. Think of it as a helpful toolkit that streamlines the process of setting up and managing web servers and routing requests.</p>
<p>In this exercise, you will be building an Express app that will:</p>
<ol>
<li><p>Handle a simple in-memory collection of movies as a RESTful resource</p>
</li>
<li><p>Support basic CRUD operations using the appropriate HTTP methods (GET, POST, PUT, DELETE)</p>
</li>
<li><p>Parse incoming JSON requests using built-in middleware</p>
</li>
<li><p>Use a custom middleware function to validate movie input before creating or updating entries</p>
</li>
<li><p>Send clear and meaningful responses based on the outcome of each request</p>
</li>
</ol>
<p>By the end, you’ll have a working API that follows REST principles and can be tested using a tool like Thunder Client or Postman.</p>
<h3 id="heading-set-up-the-express-app">Set Up the Express App</h3>
<p>To get the most out of this exercise, there are a few tools and concepts you should already be familiar with. Since we’re focusing on REST principles and how to apply them using Express, we won’t dive deep into the basics of these prerequisites. Make sure you’re comfortable with the following:</p>
<ul>
<li><p>Node.js</p>
</li>
<li><p>Npm</p>
</li>
<li><p>Thunderclient extension</p>
</li>
<li><p>Basic JavaScript</p>
</li>
</ul>
<p>With that, let’s get started.</p>
<p>Open your command prompt and create a new directory (folder):</p>
<pre><code class="lang-bash">mkdir express-app
</code></pre>
<p>Navigate into your new directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> express-app
</code></pre>
<p>Initialize an npm project:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Install the Express package in your project:</p>
<pre><code class="lang-bash">npm install express
</code></pre>
<p>Now, open your directory in your code editor with the following command:</p>
<pre><code class="lang-bash">code .
</code></pre>
<p>Create a new file, server.js, and set up your Express app in that file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> app = express();
app.use(express.json());

app.listen(<span class="hljs-number">8000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server running on port 8000'</span>));
</code></pre>
<p>This snippet above sets up a basic Express server. It starts by importing the Express library you installed, enables JSON parsing for incoming requests (so we can work with request bodies), and listens on port 3000. It’s ready to handle RESTful routes like <code>GET</code>, <code>POST</code>, <code>PUT</code>, and <code>DELETE</code> as we build out our API.</p>
<p>To start your server, go back to your command prompt and type in this command:</p>
<pre><code class="lang-bash">node server.js
</code></pre>
<p>You should see this logged in your command prompt:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744840192457/818bc1a4-3e96-4494-9895-d02cf816e3f3.png" alt="A screenshot of a command prompt or terminal window. The prompt shows the current directory as &quot;C:sersSEResktopest-tutorial>&quot;. The command &quot;node server.js&quot; has been executed, and the output below it reads &quot;Server is running on port 8000&quot;." width="600" height="400" loading="lazy"></p>
<h3 id="heading-build-restful-resources">Build RESTful Resources</h3>
<p>With our Express app set up, let’s build out the <code>/movies</code> resource using RESTful routes. We'll treat each movie as a resource and use HTTP methods to define what we want to do – retrieve, add, update, or delete movies. For simplicity, we'll store the movies in an in-memory array.</p>
<p>Here is the full set of routes. Add it in your server.js file just under your <code>app.use(express.json());</code> line:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// In-memory database (for demonstration purposes)</span>
<span class="hljs-comment">// In a real application, you would use a database like MongoDB or PostgreSQL</span>
<span class="hljs-keyword">const</span> movies = [];

<span class="hljs-comment">// Get all movies</span>
app.get(<span class="hljs-string">'/movies'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.json(movies);
  <span class="hljs-built_in">console</span>.log(movies);
});

<span class="hljs-comment">// Get a particular movie by ID</span>
app.get(<span class="hljs-string">'/movies/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> movie = movies.find(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.id === <span class="hljs-built_in">parseInt</span>(req.params.id));
  <span class="hljs-keyword">if</span> (!movie) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">'Movie not found'</span>);
  res.json(movie);
});

<span class="hljs-comment">// Add a new movie</span>
app.post(<span class="hljs-string">'/movies'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> movie = {
    <span class="hljs-attr">id</span>: movies.length + <span class="hljs-number">1</span>,
    <span class="hljs-attr">title</span>: req.body.title,
    <span class="hljs-attr">genre</span>: req.body.genre,
    <span class="hljs-attr">year</span>: req.body.year
  };
  movies.push(movie);
  res.status(<span class="hljs-number">201</span>).json(movie);
});

<span class="hljs-comment">// Update a movie</span>
app.put(<span class="hljs-string">'/movies/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> movie = movies.find(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.id === <span class="hljs-built_in">parseInt</span>(req.params.id));
  <span class="hljs-keyword">if</span> (!movie) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">'Movie not found'</span>);

  movie.title = req.body.title;
  movie.genre = req.body.genre;
  movie.year = req.body.year;

  res.json(movie);
});

<span class="hljs-comment">// Delete a movie</span>
app.delete(<span class="hljs-string">'/movies/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> movieIndex = movies.findIndex(<span class="hljs-function"><span class="hljs-params">m</span> =&gt;</span> m.id === <span class="hljs-built_in">parseInt</span>(req.params.id));
  <span class="hljs-keyword">if</span> (movieIndex === <span class="hljs-number">-1</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">'Movie not found'</span>);

  <span class="hljs-keyword">const</span> deletedMovie = movies.splice(movieIndex, <span class="hljs-number">1</span>);
  res.json(deletedMovie);
});
</code></pre>
<p>The code above defines a complete set of RESTful routes for managing a movies resource using Express.</p>
<p>It begins with an in-memory array, <code>movies</code>, which acts as our temporary data store. The <code>GET /movies</code> route returns all books, while <code>GET /movies/:id</code> looks up a book by its ID using <code>Array.find()</code>, returning a 404 status if it's not found. The <code>POST /movies</code> route accepts JSON input, creates a new book with an auto-incremented ID, and adds it to the array, returning the new resource with a <code>201 Created</code> status.</p>
<p>The <code>PUT /movies/:id</code> route handles full updates. It first finds the book, and if found, updates its <code>title</code> , <code>genre</code>, and <code>year</code> with the new values from the request body. The <code>DELETE /movies/:id</code> route removes a movie by finding its index in the array and using <code>splice()</code>. If the movie doesn't exist, both PUT and DELETE return a 404 error.</p>
<p>These routes demonstrate idempotency – that is, sending the same PUT or DELETE request multiple times will have the same effect as sending it once, a key REST principle. Each route also returns appropriate HTTP status codes and JSON responses, following REST conventions closely.</p>
<p>Each route follows a REST principle:</p>
<ul>
<li><p>Uses nouns for endpoints (<code>/movies</code>)</p>
</li>
<li><p>Uses standard HTTP methods to express actions</p>
</li>
<li><p>Ensure idempotency where appropriate (PUT, DELETE)</p>
</li>
<li><p>Return appropriate status codes and messages</p>
</li>
</ul>
<p>This structure keeps your API predictable and easy to use – exactly what REST is all about.</p>
<h3 id="heading-middlewares">Middlewares</h3>
<p>In RESTful APIs built with frameworks like Express, middleware plays a key role in maintaining clean, modular, and consistent request handling.</p>
<p>Middlewares are functions that sit in the middle of the request-response cycle in an Express app. When a client sends a request, middleware functions have access to the <code>req</code> (request), <code>res</code> (response), and <code>next</code> objects. They can inspect, modify, or act on the request before it reaches the route handler or even terminate the response early.</p>
<p>You have already seen a middleware here: <code>app.use(express.json());</code>. This is a global middleware that is used for parsing JSON. We will be creating a custom middleware for validating input for our POST and PUT requests.</p>
<p>Add the following code in your server.js file just before your routes:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Middleware for simple validation</span>
<span class="hljs-keyword">const</span> validateMovie = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!req.body.title || !req.body.genre || !req.body.year) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'Title, genre, and year are required'</span>);
  }
  next();
};
</code></pre>
<p>This middleware function, <code>validateMovie</code>, performs basic validation on incoming requests before they reach the route handler. It checks if the <code>title</code>, <code>genre</code>, and <code>year</code> fields are present in the request body. If any of these fields are missing, it immediately responds with a <code>400 Bad Request</code> status and an error message. If all required fields are provided, it calls <code>next()</code> to pass control to the next middleware or route. This keeps validation logic separate and reusable, helping maintain clean and RESTful route handlers.</p>
<p>To use this middleware, pass it as an argument in your POST and PUT routes, for example example:</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">'/movies'</span>, validateMovie, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> movie = {
    <span class="hljs-attr">id</span>: movies.length + <span class="hljs-number">1</span>,
    <span class="hljs-attr">title</span>: req.body.title,
    <span class="hljs-attr">genre</span>: req.body.genre,
    <span class="hljs-attr">year</span>: req.body.year
  };
  movies.push(movie);
  res.status(<span class="hljs-number">201</span>).json(movie);
});
</code></pre>
<h3 id="heading-test-your-express-app">Test Your Express App</h3>
<p>To test the changes you have made, you need to restart your server. Go to your command prompt and press CTRL + C (for Windows) or Command + . (for MacOS). Input the start command like before to start the server again.</p>
<p>For this exercise, you will be testing the endpoints with the Thunder Client extension on VSCode. Thunder Client is a lightweight REST API extension for VSCode. With Thunder Client, you can your REST API routes and endpoints directly in VSCode.</p>
<p>To download Thunder Client, click on the Extension icon on the taskbar on your left and search “Thunder Client”. Then click Install:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744234771851/a5d7a3e4-384b-47e9-8b2d-47bc45a2007d.png" alt="A screenshot of the Extensions Marketplace in Visual Studio Code (VS Code). The search bar at the top contains the text &quot;Thunder&quot;. Below the search bar, a list of extensions related to &quot;Thunder&quot; is displayed. The first result, &quot;Thunder Client,&quot; shows an install button. A red arrow points to the Extensions icon in the VS Code activity bar on the left, which is highlighted to indicate that this is the icon to click." width="600" height="400" loading="lazy"></p>
<p>After installation, you'll see the Thunder Client icon appear in your sidebar below the Extensions icon. Click it, then hit New Request to open a new tab. The request tab will open with a clean layout, ready for you to send and test API calls:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744282644259/dfe4b735-c465-4993-bc46-cce28966deb3.png" alt="A screenshot of the Thunder Client interface within Visual Studio Code. A new request tab is open, displaying a GET request configured to the URL &quot;https://www.thunderclient.com/welcome&quot;. The HTTP method is set to &quot;GET&quot; in a dropdown menu. Below the URL bar, tabs for &quot;Query,&quot; &quot;Headers,&quot; &quot;Auth,&quot; &quot;Body,&quot; &quot;Tests,&quot; and &quot;Pre Run&quot; are visible, with &quot;Query&quot; currently selected, showing a section for &quot;Query Parameters&quot; with fields for &quot;parameter&quot; and &quot;value&quot;. At the bottom, a message indicates &quot;Non-Commercial Use&quot; with a link to view terms. The left sidebar shows &quot;THUNDER CLIENT&quot; with options like &quot;New Request,&quot; &quot;Activity,&quot; and &quot;Collections." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>To start testing your API, set the request method (GET, POST, PUT, or DELETE) from the dropdown and enter the appropriate route, like <code>http://localhost:3000/movies</code>. For GET requests, just hit Send and you should see a response, in this case, an empty array <code>[]</code>. To get a specific movie, you include an ID (for example, <code>/movies/1</code>).</p>
<p>For <code>POST</code>, <code>PUT</code>, and <code>DELETE</code> requests, switch to the Body tab and select the JSON format. Then provide the data you want to send:</p>
<ul>
<li><p><strong>POST</strong> <code>/movies</code>: Add a new movie with <code>{"title": "Movie Title", "genre": "Genre Name", "year": 0000}</code>.</p>
</li>
<li><p><strong>PUT</strong> <code>/movies/1</code>: Update an existing movie with the same JSON structure.</p>
</li>
<li><p><strong>DELETE</strong> <code>/movies/1</code>: Remove a movie by its ID — no body is needed.</p>
</li>
</ul>
<p>After sending each request, Thunder Client will display the response body, headers, and status code. Example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744840699502/4ea83fbc-7b47-4aea-b8ff-a6e351bf54be.png" alt="A screenshot of the Thunder Client interface in Visual Studio Code, showing a successful POST request. On the left, the request details are visible: the HTTP method is set to &quot;POST&quot; with the URL &quot;http://localhost:8000/movies&quot;. The &quot;Body&quot; tab is selected, displaying JSON content: {&quot;title&quot;: &quot;Home Alone&quot;, &quot;genre&quot;: &quot;Comedy&quot;, &quot;year&quot;: 1999}. On the right, the response details indicate a &quot;Status: 201 Created&quot;, &quot;Size: 58 Bytes&quot;, and &quot;Time: 5 ms&quot;. The &quot;Response&quot; tab is selected, showing the JSON response: {&quot;id&quot;: 1, &quot;title&quot;: &quot;Home Alone&quot;, &quot;genre&quot;: &quot;Comedy&quot;, &quot;year&quot;: 1999}." width="600" height="400" loading="lazy"></p>
<h2 id="heading-bad-rest-practices-to-avoid">Bad REST Practices to Avoid</h2>
<p>When building REST APIs, aside from using the right HTTP methods, you also have to consider avoiding practices that break the core principles of REST. These bad practices can make your API harder to use, less predictable, or even misleading.</p>
<p>Here are some common REST bad practices and how to avoid them:</p>
<h3 id="heading-using-verbs-in-endpoints"><strong>Using verbs in endpoints</strong></h3>
<p>Avoid routes like <code>/getMovies</code> or <code>/createMovie</code>. RESTful APIs rely on HTTP methods to express actions, so use nouns for endpoints and let methods do the talking — for example, use <code>GET /movies</code> to retrieve movies and <code>POST /movie</code> to create one.</p>
<h3 id="heading-ignoring-http-status-codes"><strong>Ignoring HTTP status codes</strong></h3>
<p>Returning <code>200 OK</code> for every response, even errors, breaks REST conventions. Use the appropriate status codes: <code>201 Created</code> for successful POSTs, <code>404 Not Found</code> when a resource doesn’t exist, and <code>400 Bad Request</code> for validation issues. This helps clients interpret responses correctly.</p>
<h3 id="heading-overloading-a-single-endpoint"><strong>Overloading a single endpoint</strong></h3>
<p>Avoid writing one endpoint that changes behaviour based on the request body or headers. Each route should clearly map to a resource and method, like <code>GET /movies/1</code> to fetch, and <code>DELETE /movies/1</code> to remove, making the API predictable and easy to follow.</p>
<h3 id="heading-not-being-idempotent-where-expected"><strong>Not being idempotent where expected</strong></h3>
<p><code>PUT</code> and <code>DELETE</code> should be idempotent, meaning repeated requests should have the same effect. If calling <code>DELETE /movies/1</code> twice causes an error or unexpected behaviour, that’s a red flag. Design your handlers to handle these cases gracefully.</p>
<h3 id="heading-exposing-internal-logic-or-database-structure"><strong>Exposing internal logic or database structure</strong></h3>
<p>Don’t leak internal details like database table names or query logic in your route naming (<code>/api/movie_table_data</code>). Keep your URIs clean, abstracted, and centred around the actual resource, like <code>/movies</code>.</p>
<p>Avoiding these practices not only keeps your API RESTful but also improves developer experience, consistency, and long-term maintainability.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You have explored the core ideas behind REST and put them into practice by building and testing a real Express API. This hands-on approach should help bridge the gap between theory and real-world application.</p>
<p>Along the way, you learned how REST treats resources, how to write clean and predictable routes, and why these principles matter when designing APIs that are easy to use and maintain.</p>
<p>Here’s a quick recap of what you’ve built and learned:</p>
<ul>
<li><p>Defined what REST is and why it’s widely used in web development</p>
</li>
<li><p>Explored core REST principles like statelessness, resource-based routing, HTTP methods, status codes, and idempotency</p>
</li>
<li><p>Set up a simple Express server to serve as the base for a RESTful API</p>
</li>
<li><p>Built a complete set of routes (GET, POST, PUT, DELETE) for managing a <code>movies</code> resource</p>
</li>
<li><p>Used middleware for tasks like JSON parsing and input validation</p>
</li>
<li><p>Tested routes using Thunder Client and learned how to interact with each HTTP method</p>
</li>
<li><p>Identified common REST anti-patterns and how to avoid them for cleaner design</p>
</li>
</ul>
<p>To take your API further and follow more advanced RESTful practices, consider:</p>
<ul>
<li><p>Organising routes with Express Router to keep your code modular</p>
</li>
<li><p>Adding robust error handling to return consistent and informative responses</p>
</li>
<li><p>Using logging tools like <code>morgan</code> to monitor requests and debug more easily</p>
</li>
<li><p>Securing endpoints with authentication methods like JWT or API keys</p>
</li>
<li><p>Structuring responses consistently, possibly with pagination and filtering for larger datasets</p>
</li>
<li><p>Validating user input thoroughly with libraries like <code>Joi</code> or <code>express-validator</code></p>
</li>
</ul>
<p>Explore the full project on <a target="_blank" href="https://github.com/oliverTwist2/rest-tutorial">GitHub</a>, review the code, and try extending it with your features. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a REST API in Django ]]>
                </title>
                <description>
                    <![CDATA[ If you’re building a web or mobile app, chances are you’re going to need a way to send and receive data between your app and a server. That’s where REST APIs come in. They help apps talk to each other – kind of like a waiter taking your order and ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-rest-api-in-django/</link>
                <guid isPermaLink="false">67ffc4588a19b331e60a51d2</guid>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Udemezue John ]]>
                </dc:creator>
                <pubDate>Wed, 16 Apr 2025 14:53:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744814822505/5195929b-c1d8-4c9e-a12b-44697db44c5b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’re building a web or mobile app, chances are you’re going to need a way to send and receive data between your app and a server.</p>
<p>That’s where REST APIs come in. They help apps talk to each other – kind of like a waiter taking your order and bringing your food back. And if you're using Django, you're already halfway there.</p>
<p>Django is one of the most popular web frameworks out there. It’s fast, secure, and packed with useful tools. Combine it with Django REST Framework (DRF), and you’ve got everything you need to build a solid REST API without spending weeks figuring it all out.</p>
<p>In this guide, I’ll walk you through the whole process of building a REST API in Django from scratch.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-rest-api">What is a REST API?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tools-youll-need">Tools You’ll Need</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-rest-api-in-django">How to Build a REST API in Django</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-set-up-your-django-project">Step 1: Set Up Your Django Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-create-a-model">Step 2: Create a Model</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-make-a-serializer">Step 3: Make a Serializer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-create-the-views">Step 4: Create the Views</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-set-up-urls">Step 5: Set Up URLs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-test-it">Step 6: Test It!</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-drf-permissions">DRF Permissions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-common-built-in-permissions">Common Built-In Permissions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-custom-permissions">Custom Permissions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-combining-permissions">Combining Permissions</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-faqs">FAQs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-rest-api">What is a REST API?</h2>
<p>Before we get started, let’s get one thing straight: What’s even is a REST API?</p>
<p>A REST API (short for “Representational State Transfer”) is a way for two systems – like a website and a server – to talk to each other using standard HTTP methods like GET, POST, PUT, and DELETE.</p>
<p>Let’s say you have a to-do app. You want to:</p>
<ul>
<li><p><strong>Get</strong> a list of tasks</p>
</li>
<li><p><strong>Add</strong> a new task</p>
</li>
<li><p><strong>Update</strong> a task</p>
</li>
<li><p><strong>Delete</strong> a task</p>
</li>
</ul>
<p>You can do all of that through a REST API. It’s like setting up your own menu of commands that other apps (or your frontend) can use to work with your data.</p>
<h2 id="heading-tools-youll-need">Tools You’ll Need:</h2>
<p>Here’s what you’ll be using in this tutorial:</p>
<ul>
<li><p><strong>Python</strong> (preferably 3.8+)</p>
</li>
<li><p><strong>Django</strong> (web framework)</p>
</li>
<li><p><strong>Django REST Framework (DRF)</strong> (to build APIs)</p>
</li>
<li><p><strong>Postman or curl</strong> (for testing)</p>
</li>
</ul>
<p>You can install DRF with:</p>
<pre><code class="lang-bash">pip install djangorestframework
</code></pre>
<h2 id="heading-how-to-build-a-rest-api-in-django"><strong>How to Build a REST API in Django</strong></h2>
<p>Here is how to get started:</p>
<h3 id="heading-step-1-set-up-your-django-project">Step 1: Set Up Your Django Project</h3>
<p>If you haven’t already, start a new Django project:</p>
<pre><code class="lang-bash">django-admin startproject myproject
<span class="hljs-built_in">cd</span> myproject
python manage.py startapp api
</code></pre>
<ul>
<li><p><code>django-admin startproject myproject</code> – Creates a new Django project named <code>myproject</code>, which contains configuration files for your whole site.</p>
</li>
<li><p><code>cd myproject</code> – Move into your new project directory.</p>
</li>
<li><p><code>python</code> <a target="_blank" href="http://manage.py"><code>manage.py</code></a> <code>startapp api</code> – Creates a new Django app named <code>api</code> where your models, views, and API logic will live.</p>
</li>
</ul>
<p>Now add <code>'rest_framework'</code> and <code>'api'</code> to your <code>INSTALLED_APPS</code> in <code>settings.py</code>:</p>
<pre><code class="lang-python">INSTALLED_APPS = [
    ...
    <span class="hljs-string">'rest_framework'</span>,
    <span class="hljs-string">'api'</span>,
]
</code></pre>
<ul>
<li><p><code>rest_framework</code> is the Django REST Framework – it gives you tools to easily create APIs.</p>
</li>
<li><p><code>'api'</code> tells Django to look in the <code>api</code> folder for models, views, and so on.</p>
</li>
</ul>
<h3 id="heading-step-2-create-a-model">Step 2: Create a Model</h3>
<p>Let’s make a simple model – a task list.</p>
<p>In <code>api/models.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span>(<span class="hljs-params">models.Model</span>):</span>
    title = models.CharField(max_length=<span class="hljs-number">200</span>)
    completed = models.BooleanField(default=<span class="hljs-literal">False</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.title
</code></pre>
<ul>
<li><p><code>title</code>: A short piece of text (like “Buy groceries”). <code>CharField</code> is used for strings.</p>
</li>
<li><p><code>completed</code>: A Boolean (True or False) to mark if a task is done.</p>
</li>
<li><p><code>__str__</code>: This special method returns a string version of the model when printed – useful for debugging and the admin panel.</p>
</li>
</ul>
<p>Then run:</p>
<pre><code class="lang-bash">python manage.py makemigrations
python manage.py migrate
</code></pre>
<ul>
<li><p><code>makemigrations</code>: Prepares the changes to the database schema.</p>
</li>
<li><p><code>migrate</code>: Applies those changes to the actual database.</p>
</li>
</ul>
<h3 id="heading-step-3-make-a-serializer">Step 3: Make a Serializer</h3>
<p>Serializers turn your Django model into JSON (the data format used in APIs) and back.</p>
<p>In <code>api/serializers.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> serializers
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Task

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskSerializer</span>(<span class="hljs-params">serializers.ModelSerializer</span>):</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = Task
        fields = <span class="hljs-string">'__all__'</span>
</code></pre>
<ul>
<li><p><strong>Serializers</strong> convert model instances (like a <code>Task</code>) to and from <strong>JSON</strong>, so they can be sent over the web.</p>
</li>
<li><p><code>ModelSerializer</code> is a shortcut that automatically handles most things based on your model.</p>
</li>
<li><p><code>fields = '__all__'</code> means include every field in the model (title and completed).</p>
</li>
</ul>
<h3 id="heading-step-4-create-the-views">Step 4: Create the Views</h3>
<p>Here’s where the logic goes. You can use class-based or function-based views. Let’s go with class-based using DRF’s <code>generics</code>.</p>
<p>In <code>api/views.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework <span class="hljs-keyword">import</span> generics
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Task
<span class="hljs-keyword">from</span> .serializers <span class="hljs-keyword">import</span> TaskSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskListCreate</span>(<span class="hljs-params">generics.ListCreateAPIView</span>):</span>
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskDetail</span>(<span class="hljs-params">generics.RetrieveUpdateDestroyAPIView</span>):</span>
    queryset = Task.objects.all()
    serializer_class = TaskSerializer
</code></pre>
<p>These are <strong>generic class-based views</strong> provided by Django REST Framework to save you time.</p>
<ol>
<li><p><code>TaskListCreate</code>:</p>
<ul>
<li><p>Handles GET requests to list all tasks.</p>
</li>
<li><p>Handles POST requests to create new tasks.</p>
</li>
</ul>
</li>
<li><p><code>TaskDetail</code>:</p>
<ul>
<li>Handles GET for one task, PUT/PATCH for updating, and DELETE to remove a task</li>
</ul>
</li>
</ol>
<h3 id="heading-step-5-set-up-urls">Step 5: Set Up URLs</h3>
<p>First, make a <code>urls.py</code> file in the <code>api</code> folder (if it doesn’t exist).</p>
<p>In <code>api/urls.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> .views <span class="hljs-keyword">import</span> TaskListCreate, TaskDetail

urlpatterns = [
    path(<span class="hljs-string">'tasks/'</span>, TaskListCreate.as_view(), name=<span class="hljs-string">'task-list'</span>),
    path(<span class="hljs-string">'tasks/&lt;int:pk&gt;/'</span>, TaskDetail.as_view(), name=<span class="hljs-string">'task-detail'</span>),
]
</code></pre>
<ul>
<li><p><code>tasks/</code>: The route to access or create tasks.</p>
</li>
<li><p><code>tasks/&lt;int:pk&gt;/</code>: The route to get, update, or delete a single task by its primary key (<code>pk</code>).</p>
</li>
</ul>
<p>Then, in your main <code>myproject/</code><a target="_blank" href="http://urls.py"><code>urls.py</code></a>:</p>
<p>Now, hook this into the main <code>urls.py</code> in your project folder:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include

urlpatterns = [
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
    path(<span class="hljs-string">'api/'</span>, include(<span class="hljs-string">'api.urls'</span>)),
]
</code></pre>
<h3 id="heading-step-6-test-it">Step 6: Test It!</h3>
<p>Start the server:</p>
<pre><code class="lang-bash">python manage.py runserver
</code></pre>
<p>Open Postman or curl and try hitting these endpoints:</p>
<ul>
<li><p><code>GET /api/tasks/</code> – get all tasks</p>
</li>
<li><p><code>POST /api/tasks/</code> – create a new task</p>
</li>
<li><p><code>GET /api/tasks/1/</code> – get a specific task</p>
</li>
<li><p><code>PUT /api/tasks/1/</code> – update a task</p>
</li>
<li><p><code>DELETE /api/tasks/1/</code> – delete a task</p>
</li>
</ul>
<p>And that’s it – you’ve got a working REST API.</p>
<p>This setup gives you a fully functional REST API with just a few lines of code, thanks to Django REST Framework. You should now understand:</p>
<ul>
<li><p>How models define your database structure</p>
</li>
<li><p>How serializers turn models into JSON and vice versa</p>
</li>
<li><p>How views control API behaviour (get, post, update, delete)</p>
</li>
<li><p>How URL routing connects your views to web requests</p>
</li>
</ul>
<h2 id="heading-drf-permissions">DRF Permissions</h2>
<p>Right now, anyone can use your API. But what if you only want certain users to have access?</p>
<p>DRF gives you simple ways to handle this. For example, to make an API only available to logged-in users:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> IsAuthenticated

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskListCreate</span>(<span class="hljs-params">generics.ListCreateAPIView</span>):</span>
    ...
    permission_classes = [IsAuthenticated]
</code></pre>
<p>There are more permissions you can use, like <code>IsAdminUser</code> custom permissions, for example.</p>
<p>Let’s break this down and go deeper into <strong>permissions</strong> in Django REST Framework (DRF), including:</p>
<h3 id="heading-what-are-permissions-in-drf">What are Permissions in DRF?</h3>
<p>Permissions in DRF control <strong>who</strong> can access your API and <strong>what actions</strong> they can perform (read, write, delete, etc.).</p>
<p>They’re applied per view (or viewset), and they're checked after authentication, meaning they build on top of checking whether the user is logged in.</p>
<h3 id="heading-common-built-in-permissions">Common Built-In Permissions</h3>
<p>DRF gives you a few super useful built-in permission classes out of the box:</p>
<h4 id="heading-1-isauthenticated">1. <code>IsAuthenticated</code></h4>
<p>This one ensures that only logged-in users can access the view:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> IsAuthenticated

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskListCreate</span>(<span class="hljs-params">generics.ListCreateAPIView</span>):</span>
    queryset = Task.objects.all()
    serializer_class = TaskSerializer
    permission_classes = [IsAuthenticated]
</code></pre>
<p>Only users who have been authenticated (for example, via session login or token) will be able to list or create tasks. Anyone else gets a <code>403 Forbidden</code> response.</p>
<h4 id="heading-2-isadminuser">2. <code>IsAdminUser</code></h4>
<p>Only allows access if <code>user.is_staff</code> is <code>True</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> IsAdminUser

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdminOnlyView</span>(<span class="hljs-params">generics.ListAPIView</span>):</span>
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]
</code></pre>
<p>Only admin users (usually set via Django admin or superuser status) can access this view.</p>
<h4 id="heading-3-allowany">3. <code>AllowAny</code></h4>
<p>Allows <strong>all</strong> users, even unauthenticated ones. This is the default for open APIS like sign-up pages.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> AllowAny

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PublicSignupView</span>(<span class="hljs-params">generics.CreateAPIView</span>):</span>
    serializer_class = SignupSerializer
    permission_classes = [AllowAny]
</code></pre>
<h4 id="heading-4-isauthenticatedorreadonly">4. <code>IsAuthenticatedOrReadOnly</code></h4>
<p>Authenticated users can read and write, unauthenticated users can only read (GET, HEAD, OPTIONS).</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> IsAuthenticatedOrReadOnly

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleView</span>(<span class="hljs-params">generics.RetrieveUpdateAPIView</span>):</span>
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
</code></pre>
<p><strong>Use case:</strong> Great for blogs or article APIS where the public can read but only registered users can write/update.</p>
<h3 id="heading-custom-permissions">Custom Permissions</h3>
<p>Want more control? You can create your permissions by subclassing <code>BasePermission</code>.</p>
<h4 id="heading-example-only-allow-owners-of-an-object-to-edit-it">Example: Only allow owners of an object to edit it</h4>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> rest_framework.permissions <span class="hljs-keyword">import</span> BasePermission

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IsOwner</span>(<span class="hljs-params">BasePermission</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">has_object_permission</span>(<span class="hljs-params">self, request, view, obj</span>):</span>
        <span class="hljs-keyword">return</span> obj.owner == request.user
</code></pre>
<p>Then use it like this:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TaskDetailView</span>(<span class="hljs-params">generics.RetrieveUpdateDestroyAPIView</span>):</span>
    queryset = Task.objects.all()
    serializer_class = TaskSerializer
    permission_classes = [IsAuthenticated, IsOwner]
</code></pre>
<ul>
<li><p>First, a user must be logged in (<code>IsAuthenticated</code>).</p>
</li>
<li><p>Then, only the owner of that specific <code>Task</code> can view, update, or delete it.</p>
</li>
</ul>
<h3 id="heading-combining-permissions">Combining Permissions</h3>
<p>You can combine multiple permission classes, and all must return <code>True</code> for access to be granted.</p>
<pre><code class="lang-python">permission_classes = [IsAuthenticated, IsAdminUser]
</code></pre>
<p>This means: user must be both authenticated and an admin.</p>
<h4 id="heading-tldr">TL;DR</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Permission</td><td>Who Gets Access?</td></tr>
</thead>
<tbody>
<tr>
<td><code>AllowAny</code></td><td>Everyone (even logged-out users)</td></tr>
<tr>
<td><code>IsAuthenticated</code></td><td>Only logged-in users</td></tr>
<tr>
<td><code>IsAdminUser</code></td><td>Only admin/staff users</td></tr>
<tr>
<td><code>IsAuthenticatedOrReadOnly</code></td><td>Read: everyone / Write: only logged-in users</td></tr>
<tr>
<td><code>Custom Permissions</code></td><td>Your rules (e.g., only owners)</td></tr>
</tbody>
</table>
</div><h2 id="heading-faqs">FAQs</h2>
<h3 id="heading-do-i-need-django-rest-framework-to-build-an-api-in-django"><strong>Do I need Django REST Framework to build an API in Django?</strong></h3>
<p>Technically, no – but DRF makes your life much easier. Without DRF, you'd have to manually handle things like:</p>
<ul>
<li><p>Parsing and validating JSON requests</p>
</li>
<li><p>Writing views to serialise Python objects to JSON</p>
</li>
<li><p>Managing HTTP status codes and responses</p>
</li>
<li><p>Handling authentication and permissions on your own</p>
</li>
</ul>
<p>In short, you’d be reinventing the wheel – but DRF does all of this for you with far less code.</p>
<h3 id="heading-can-i-use-this-api-with-a-react-or-vue-frontend"><strong>Can I use this API with a React or Vue frontend?</strong></h3>
<p>Absolutely. Your Django API will send and receive data in JSON format — which is exactly what modern frontend frameworks like React and Vue are designed to work with. Just make sure you handle CORS (Cross-Origin Resource Sharing) correctly.</p>
<h3 id="heading-how-do-i-make-my-api-faster"><strong>How do I make my API faster?</strong></h3>
<p>You can:</p>
<ul>
<li><p>Use <strong>caching</strong> to store frequent responses</p>
</li>
<li><p>Enable <strong>pagination</strong> to reduce data load</p>
</li>
<li><p>Explore <strong>async views</strong> (Django 3.1+ supports async) for faster I/O<br>  DRF also offers built-in tools for pagination, throttling, and more performance tweaks out of the box.</p>
</li>
</ul>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Building a REST API in Django might sound like a big job, but it’s just a series of small, manageable steps.</p>
<p>Once you’ve done it once, it gets way easier the next time. Plus, using Django REST Framework saves a ton of time—you’re not reinventing the wheel every time.</p>
<h3 id="heading-further-resources">Further Resources</h3>
<p>Want to keep learning? Here are a few solid places to dig deeper:</p>
<ul>
<li><p><a target="_blank" href="https://www.django-rest-framework.org/">Official Django REST Framework Docs</a></p>
</li>
<li><p><a target="_blank" href="https://docs.djangoproject.com/en/stable/">Django’s Official Docs</a></p>
</li>
<li><p><a target="_blank" href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/">Simple JWT for token authentication</a></p>
</li>
<li><p><a target="_blank" href="https://www.postman.com/">Test your API with Postman</a></p>
</li>
<li><p><a target="_blank" href="https://realpython.com/django-rest-framework-quick-start/">Real Python’s Django API Guide</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Deploy a Restful Web Service on Microsoft Azure App Service ]]>
                </title>
                <description>
                    <![CDATA[ Hey there! 👋, How’s it going? I hope you're doing well. Whether you're a seasoned coder, a curious learner, or just someone browsing through, welcome to my little corner of the internet. In this tutorial, we’ll dive into how you can deploy a web ser... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/deploy-a-restful-web-service-on-microsoft-azure-app-service/</link>
                <guid isPermaLink="false">67e6c180423cd4f90a6350b5</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ azure-devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Azure App Service ]]>
                    </category>
                
                    <category>
                        <![CDATA[ azure-app-services ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alaran Ayobami ]]>
                </dc:creator>
                <pubDate>Fri, 28 Mar 2025 15:34:24 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743176028047/61eba7a3-5505-4152-9df5-59a1cb8c61ac.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey there! 👋, How’s it going?</p>
<p>I hope you're doing well. Whether you're a seasoned coder, a curious learner, or just someone browsing through, welcome to my little corner of the internet.</p>
<p>In this tutorial, we’ll dive into how you can deploy a web service on Microsoft Azure app service. It’s a topic I’ve been excited to explore, and I hope you’ll find it insightful and helpful. So grab a coffee, sit back, and let’s get started.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li><p>Basic understanding of RESTful web services</p>
</li>
<li><p>Programming knowledge</p>
</li>
<li><p>Docker basics</p>
</li>
<li><p>Docker Hub account</p>
</li>
<li><p>Command Line Interface (CLI) skills</p>
</li>
</ul>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-key-terminologies">Key Terminologies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-docker-and-docker-compose">How to Install Docker and Docker Compose</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-simple-get-client-info-web-service">How to Create a Simple Get Client Info Web Service</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-apps-docker-image">How to Build the App’s Docker Image</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-run-the-app-in-the-container">How to Run the App in the Container</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-an-azure-resource-group-on-azure-portal">How to Create an Azure Resource Group on Azure Portal.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-to-azure-app-service">How to Deploy to Azure App Service</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<p>Before we actually get started, I’d like to go over some key terminologies that I'll be using throughout this tutorial. Understanding these terms will make it easier to follow along and get the most out of what we're discussing. Let’s dive in!</p>
<h2 id="heading-key-terminologies">Key Terminologies</h2>
<h3 id="heading-1-docker"><strong>1. Docker</strong></h3>
<p>Docker is an open-source platform that simplifies application development, shipping, and deployment by using containers. With Docker, there are three key things you can do:</p>
<ul>
<li><p>build once and run anywhere</p>
</li>
<li><p>keep environment consistent, and</p>
</li>
<li><p>easily scale your application with container orchestration tools like Kubernetes.</p>
</li>
</ul>
<h3 id="heading-2-docker-hub"><strong>2. Docker Hub</strong></h3>
<p>Docker Hub is a cloud-based repository where developers can store, share, and manage Docker images. You can think of it as the GitHub for Docker images 😉.</p>
<h3 id="heading-3-docker-image"><strong>3. Docker Image</strong></h3>
<p>A Docker image is a lightweight<strong>,</strong> standalone, and executable package that includes everything needed to run a piece of software. You can also think of it as a blueprint for creating and running a container.</p>
<p>Once built, an image is immutable, meaning it cannot change after creation. Instead, you create a new version when updates are needed. This means that you’ll need to rebuild if you update the code that’s being run in the container.</p>
<h3 id="heading-4-container"><strong>4. Container</strong></h3>
<p>A container is a running instance of a Docker image. It provides an isolated environment where an application runs with all its dependencies, without interfering with the host system or other containers.</p>
<p>Wait, what?! <strong>😕</strong> Well, simply put, a container is like a tiny virtual machine that runs the built Docker image. But unlike traditional VMs, it has no init process (PID 1), meaning it always runs on a host system rather than being fully independent. By now, you should be getting the idea: no image, no container. A container depends on an image to exist. You have to cook before you serve, right? 🍽️</p>
<h3 id="heading-5-azure-resource-group"><strong>5. Azure Resource Group</strong></h3>
<p>An Azure resource group refers to a store or folder containing all related resources for an application you want to deploy to production using MS Azure Cloud. For example, if I want to deploy an eCommerce web app with MS Azure, I could create a resource group called EcommWebAppRG. I’d use this to create all the resources I needed for the web app to go live and be accessible – like VMs, DBs, caches, and other services.</p>
<p>Alrighty, now that all the terms are out of the way, lets get started with the tutorial so you can learn how to deploy a web service on Azure App Service.</p>
<p>Since we are deploying an app, let’s start by creating simple REST API app. I’ll be using Golang for the API development, but you can use any programming language/framework of your choice. If you’d like to follow along with the app for this tutorial, I’ve provided the source code <a target="_blank" href="https://github.com/Ayobami6/client_info_webservice">here</a>.</p>
<h2 id="heading-how-to-install-docker-and-docker-compose">How to Install Docker and Docker Compose</h2>
<p>To install Docker and Docker compose on your PC, for Mac and Windows you’ll need to download Docker desktop for your Operating System <a target="_blank" href="https://hub.docker.com/welcome">here</a>.</p>
<p>For Linux, you can run the following command:</p>
<pre><code class="lang-bash">sudo apt update <span class="hljs-comment"># update apt registry</span>
sudo apt install docker.io <span class="hljs-comment"># for docker engine</span>
sudo apt install docker-compose-plugin
</code></pre>
<p>After downloading the Docker desktop for your application, open your terminal and enter the following command to verify that Docker and Docker Compose have been successfully installed on your machine:</p>
<pre><code class="lang-bash">docker-compose -v <span class="hljs-comment"># this should show the version of docker compose cli you have on your PC</span>
</code></pre>
<p>My Docker Compose version is:</p>
<pre><code class="lang-bash">Docker Compose version v2.31.0-desktop.2
</code></pre>
<pre><code class="lang-bash">docker -v
</code></pre>
<p>You should see something similar if Docker has successfully been installed on your machine:</p>
<pre><code class="lang-bash">Docker version 27.4.0, build bde2b89
</code></pre>
<h2 id="heading-how-to-create-a-simple-get-client-info-web-service">How to Create a Simple Get Client Info Web Service</h2>
<p>Alright, I’ll use this handy tool called <code>sparky_generate</code> to generate the app code template. <code>sparky_generate</code> is a command line tool used to generate boilerplate code for backend development using various backend languages and frameworks.</p>
<p>Use this command to install and setup the tool on your Mac or Linux machine. If you are on Windows, you can use WSL.</p>
<pre><code class="lang-bash">wget https://raw.githubusercontent.com/Ayobami6/sparky_generate/refs/heads/main/install.sh
</code></pre>
<pre><code class="lang-bash">chmod 711 install.sh
./install.sh <span class="hljs-comment"># run the install command like so</span>
</code></pre>
<pre><code class="lang-bash">sparky <span class="hljs-comment"># run the sparky command like so</span>
</code></pre>
<p>You should see something similar to the below. Select whatever framework you want to use for your backend service.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741520002226/b696a376-527b-412a-a8c7-967aca35217a.png" alt="Choose a project type in sparky" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>I will select Go, because I’m using Go for this tutorial. You should have your project template ready once you’ve selected your framework. I won’t go through how to code the web service since it’s out of scope for this tutorial. The goal here is to deploy on Azure using Azure App Service.</p>
<h2 id="heading-how-to-build-the-apps-docker-image">How to Build the App’s Docker Image</h2>
<p>To build the Docker image for our app, we first need to create a Docker file that will include all the steps needed to build the image.</p>
<pre><code class="lang-bash">touch Dockerfile
</code></pre>
<p>We will be using a multistage Docker build to reduce the size of our Docker image. We need something as light as possible.</p>
<p>The multistage Docker build helps reduce size because we use different stages for different concerns. This helps ensure that only what’s needed runs the application in the final stage. For example, we might need certain artifacts to build the application, but we don’t need them to run the application. This is why we have the builder and runner stages in the Docker file below.</p>
<p>Our first stage (build) is concerned with building and bundling the application. The second stage (runner) is just used to run the executable we built in the first stage. So basically all files, modules, and so on used in the build process will be discarded in the runner since they’ve already served their purposes.</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># using the first stage as build</span>
<span class="hljs-keyword">FROM</span> golang:<span class="hljs-number">1.23</span>-alpine AS build <span class="hljs-comment"># using alpine base image to reduce size</span>

<span class="hljs-comment"># install git on the machine</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apk add --no-cache git</span>

<span class="hljs-comment"># setting the current work directory on the vm to be /app</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copying all go dependency files to the working directory</span>
<span class="hljs-keyword">COPY</span><span class="bash"> go.mod go.sum ./</span>

<span class="hljs-comment"># Install go dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> go mod download</span>

<span class="hljs-comment"># copy all remaining files to the working directory</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-comment"># build the execuatable</span>

<span class="hljs-comment"># build the go program</span>
<span class="hljs-keyword">RUN</span><span class="bash"> go build -o api cmd/main.go</span>

<span class="hljs-comment"># stage 2 AKA the runner</span>
<span class="hljs-keyword">FROM</span> alpine:<span class="hljs-number">3.18</span>

<span class="hljs-keyword">RUN</span><span class="bash">  apk add --no-cache ca-certificates</span>

<span class="hljs-comment"># copy the go executable to the working directory</span>
<span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/api .</span>

<span class="hljs-comment"># expose the service running port</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">6080</span>
</code></pre>
<p>This Dockerfile outlines all the steps for building a Docker image for our app. Lets go through all these steps line by line. Because we are using a multistage build here, our stages are <code>build</code> and <code>runner</code>.</p>
<ul>
<li><p>The first stage build starts from the first <code>FROM golang:1.23-alpine AS build</code>. It initializes a stage with all the steps in the stage. It states that the base image to be used for all the steps in this stage should use a pre-existing golang:1.23 image using an Alpine Linux distro to run all the steps in the stage.</p>
</li>
<li><p>Next, we have <code>RUN</code>, which is used to run the command <code>apk add git</code>, followed by setting the working directory to the /app folder.</p>
</li>
<li><p>Then we have the <code>COPY</code> command that copies all the Go dependencies that will run the Go program.</p>
</li>
<li><p>Following that is <code>RUN go mod download</code> which is used to install all the dependencies.</p>
</li>
<li><p>We then have the command <code>COPY . .</code> to copy all the files to the working directory /app of the image</p>
</li>
<li><p>Then the last step in the build stage, <code>RUN go build -o api cmd/main.go</code>, builds the app code main.go to an executable API. The second stage “runner“ uses an <code>alpine:3.18</code> base image, and also uses the <code>RUN</code> directive to add ca-certificates to the Alpine base image. The <code>COPY</code> is used here to copy just the built executable file from the builder image to the runner image.</p>
</li>
<li><p>We then expose port 6080 so our built container can accept an HTTP connection from port 6080.</p>
</li>
</ul>
<p>Now, let’s write our <code>docker-compose.yml</code> file to define and run our containerized service::</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>

  <span class="hljs-attr">client_info_app:</span>
    <span class="hljs-attr">build:</span> 
      <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
      <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">info_app</span>

    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"6080:6080"</span>

    <span class="hljs-attr">command:</span> <span class="hljs-string">"./api"</span>
</code></pre>
<h3 id="heading-understanding-the-yaml-structure">Understanding the YAML Structure</h3>
<p>YAML follows a key-value structure similar to a dictionary or hashmap. In our file, the top-level key is <code>services</code>, which acts as the parent key. Within <code>services</code>, we define individual service configurations.</p>
<p>In this case, we have a single service named <code>client_info_app</code>, which contains the necessary properties for Docker to build and run it.</p>
<ul>
<li><p><code>build</code>: This specifies how to build the Docker image for the service. The <code>context: .</code> tells Docker to look for the <code>Dockerfile</code> in the same directory as the <code>docker-compose.yml</code> file.</p>
</li>
<li><p><code>container_name</code>: This assigns a custom name (<code>info_app</code>) to the running container, making it easier to reference.</p>
</li>
<li><p><code>ports</code>: Defines the port mappings between the host and the container. The <code>-</code> before <code>"6080:6080"</code> indicates that multiple mappings could be listed. Here, port <code>6080</code> on the host is mapped to port <code>6080</code> inside the container.</p>
</li>
<li><p><code>command</code>: Specifies the command to execute inside the container once it starts. In this case, it runs <code>./api</code>.</p>
</li>
</ul>
<p>This structure allows us to define and configure multiple services within the <code>services</code> key if needed, but for now, we are only defining <code>client_info_app</code>.</p>
<h2 id="heading-how-to-run-the-app-in-the-container">How to Run the App in the Container</h2>
<p>You can use this command to start the container:</p>
<pre><code class="lang-bash">docker-compose up client_info_app
</code></pre>
<p>The above command will first build the image if it doesn’t exist. Then it runs it, because remember: <strong>no image, no container.</strong></p>
<p>If all looks good, you should have something similar to this, depending on your application framework:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741708248802/0c0e25a0-fa8c-4eea-adaa-5f4986b5fda6.png" alt="Go running webserver" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You should also verify that your Docker image has been built as well. To do that, run the following:</p>
<pre><code class="lang-bash">docker images
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741708480967/dbb033eb-d336-4f22-934b-8d50333b6344.png" alt="Verify that Docker is successfully built" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Voilà! You now have your Docker image built and ready for deployment on Azure App Service.</p>
<p>Let’s go on to the Azure Portal to deploy the app.</p>
<p><strong>Note:</strong> if you don’t have an active Azure Subscription, that’s fine – you can still follow along. If you want to get a trial account, you can <a target="_blank" href="https://azure.microsoft.com/en-us/pricing/purchase-options/azure-account">get one here</a>.</p>
<h2 id="heading-how-to-create-an-azure-resource-group-on-azure-portal">How to Create an Azure Resource Group on Azure Portal.</h2>
<p>As a reminder, an Azure resource group refers to a store or folder containing all related resources for an application you want to deploy to production using MS Azure Cloud. Now let’s go about creating one.</p>
<p>When you login to the Azure portal, you should see some like this, the dashboard:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741709173044/1ab78dd4-97ac-43da-8599-d7b1d790eb13.png" alt="Azure dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Search for Resource group using the search bar:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741709263175/7946270b-11c6-4fef-9abc-996b1efc6f52.png" alt="Search for resource group" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741709619363/5cfce825-0af6-4d64-ae4e-e929ba03d919.png" alt="Resource group control pane" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Click on Create to create a new resource group:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741709715096/e519fe55-0ac3-4e9f-8b98-3f34cecfcd43.png" alt="Create a resource group" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Give your resource group a name and select a region for it. Here I will use the default East US 2, but you can use any you want. Then click on Review + create.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741770354937/253c33d2-d7b2-44b5-84df-9cb4977aec3b.png" alt="Review resource group creation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741770386424/0a97c949-5c31-466b-be7f-a43f0783e125.png" alt="Resource group overview" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You should see something like the above after creating the resource group.</p>
<h2 id="heading-how-to-deploy-to-azure-app-service">How to Deploy to Azure App Service</h2>
<p>Ok now that we’ve created the resource group, let’s go ahead and create the Azure App Service. To do this, navigate back to the dashboard and click on Create a resource.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741772709338/2c353749-7e0a-42b0-894e-25b1f08cad15.png" alt="Azure dashboard" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741773327784/536358ff-241b-4ea1-876d-575abf12a27b.png" alt="Azure resources view" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can search for Web App if you don’t see it in the list there. Then click on the Create Web App option:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741855971071/8c120d54-1df1-41f3-85b2-c03d9fd709f1.png" alt="Create a web app" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here, select the resource group you created earlier, give the app a name, then select Container for the Publish option.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741882867790/bed19e70-726d-4696-b88f-754e36511f0a.png" alt="Web app creation configuration" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Before you click on Create, go back to your dev workspace (VS Code or whatever IDE you are using) to push your Docker image to Docker Hub so you can add it there before proceeding to the next steps.</p>
<p>But why do you need to push to Docker Hub? Well, first of all, for accessibility – so we can easily share it with others or have other services access it (which is what we need here).</p>
<p>Remember how I compared Docker Hub with Github earlier? Docker Hub helps you host your Docker image on the internet and make it available for others or for various services on the internet to access if you make it public. Otherwise it’s limited to only authorized services.</p>
<p>To push the Docker image to Docker Hub, you first need to tag the Docker image with your Docker Hub username. Go to Docker <a target="_blank" href="https://hub.docker.com/">Docker Hub</a> to register and get your username if you don’t have one.</p>
<p>Run the following:</p>
<pre><code class="lang-bash">docker tag client_info_webservice-client_info_app:latest ayobami6/client_info_webservice-client_info_app:latest
<span class="hljs-comment"># this adds the latest tag to your docker image</span>
</code></pre>
<p>This shows that you successfully tagged your image with the latest tag.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741941521765/f624e0d1-2380-41cc-8bbf-f05e55d0b0ad.png" alt="Tagged Docker images" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Before you actually push the image to Docker Hub, go ahead and login to it with the Docker CLI.</p>
<pre><code class="lang-bash">docker login <span class="hljs-comment"># this will prompt for browser authetication, for the prompt and login your account with your usernam and password</span>
</code></pre>
<p>Push the image to Docker Hub like this:</p>
<pre><code class="lang-bash">docker push ayobami6/client_info_webservice-client_info_app:latest
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741941723747/5947d1eb-82fe-4bf3-a0d7-e20bbc9d7de4.png" alt="Push Docker image to Docker Hub" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You should see something like the below once you enter the push command on Docker Hub.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741941947561/7050ed8b-b7bf-4e07-91a6-765549b5d715.png" alt="Verify Docker image on Docker Hub" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Alright, now that you have the Docker image on Docker Hub, you can go ahead and deploy it using Microsoft Azure App Service.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741944017329/32080357-e214-4864-b5cb-0fc8ad77a71f.png" alt="Create web container selection for publish" class="image--right mx-auto mr-0" width="600" height="400" loading="lazy"></p>
<p>Click on the container on the top menu bar to configure the container settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741944418747/6f9092e9-e6fc-4098-86d0-ba79eda37a58.png" alt="Container section of Azure web app" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here, select Other container registries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741944507676/d4c3d17e-e3fa-4c43-99b5-b768fd900309.png" alt="Other registry selection for Azure web app" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Select public, because your pushed image is public (meaning it’s publicly accessible over the internet).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743071959687/48cc5a78-4b72-4c8f-9ffb-d32c065e1a63.jpeg" alt="Docker image access type selection" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Add your Docker image and tag. You can get this when you run the command <code>docker images</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743072606918/d17f7a31-bee3-41b9-a685-d7de0c0f6b39.jpeg" alt="Image and tag selection" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<pre><code class="lang-bash">λ MACs-MacBook-Pro ~ → docker images
REPOSITORY                                        TAG         IMAGE ID       CREATED         SIZE
ayobami6/client_info_webservice-client_info_app   latest      a14f2a5b3bd4   2 weeks ago     30.8MB
postgres                                          13-alpine   236985828131   4 weeks ago     383MB
glint_pm_frontend-nextjs                          latest      424233ceaa4b   4 weeks ago     1.72GB
flask_app-flask_app                               latest      ff6ecfc4ba5a   5 weeks ago     203MB
nginx                                             latest      124b44bfc9cc   7 weeks ago     279MB
encoredotdev/postgres                             15          58b55b0e1fc7   10 months ago   878MB
λ MACs-MacBook-Pro ~ →
</code></pre>
<p>Copy the repository name and tag – in my case I have <code>ayobami6/client_info_webservice-client_info_app</code> and tag <code>latest</code> → <code>ayobami6/client_info_webservice-client_info_app:latest</code>.</p>
<p>Then add your startup command. If you are not using Go for the development like I am, your startup command will be different – so just use the command you added to your Docker compose command key, like so <code>command: "./api"</code>. Copy just the value (mine is .<code>/api</code>) don’t add the double quotes, and add it to the startup command.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743072910308/a208c0a1-718b-4725-99b5-47bf33691fca.jpeg" alt="Add startup command to the web app container configuration" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This start up command is the command that will start the application from the container and get the container running.</p>
<p>Click on review and create to create the service.</p>
<p>Once the deployment is complete you’ll be redirected here:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741944994364/31e051a6-2da1-46fa-a748-c2bdd20528be.png" alt="Web app overview" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Congratulations! You’ve successfully deployed your web service to Azure App Service. You can visit your app using the default domain from the overview. Mine is <a target="_blank" href="http://clientinfoapp-hdgcdmgjdyd5ecfy.canadacentral-01.azurewebsites.net">here</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741945313388/19c73507-0b48-49ef-9885-515784cb0f9b.png" alt="Deployed service test on Postman" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741945461019/30a668c7-0552-4905-bbb0-c9db0b587387.png" alt="Deployed service test on web browser" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Deploying a RESTful web service on Microsoft Azure App Service is a powerful way to leverage cloud technology for scalable and efficient application hosting.</p>
<p>Understanding key terms like Docker, Docker Hub, and Azure Resource Groups will help you streamline the deployment process.</p>
<p>This guide walked you through creating a simple web service, building a Docker image, and deploying it on Azure. By following these steps, you can confidently deploy your applications, ensuring they are accessible and performant.</p>
<p>Thank you for following along, and I hope this tutorial has been insightful and helpful in your cloud deployment journey. If you found it useful, feel free to share it with others who might benefit from it. Happy coding and deploying!</p>
<p>Stay tuned for more insightful content, and let's continue learning and growing together. Cheers to building smarter, more efficient solutions with Azure.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work with OpenAPI in Go ]]>
                </title>
                <description>
                    <![CDATA[ Well-structured and well-documented APIs are a pleasure to work with. And nowadays the standard is OpenAPI, which comes with a good methodology for defining an API interface first, and only then constructing everything around it. This makes it easier... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-work-with-openapi-in-go/</link>
                <guid isPermaLink="false">67b5da4da9d7e29052110938</guid>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OpenApi ]]>
                    </category>
                
                    <category>
                        <![CDATA[ swagger ]]>
                    </category>
                
                    <category>
                        <![CDATA[ RESTful APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Pliutau ]]>
                </dc:creator>
                <pubDate>Wed, 19 Feb 2025 13:19:09 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740164911110/7954a7d5-39dc-4504-82eb-f5fe583b7b84.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Well-structured and well-documented APIs are a pleasure to work with. And nowadays the standard is <a target="_blank" href="https://www.openapis.org/">OpenAPI</a>, which comes with a good methodology for defining an API interface first, and only then constructing everything around it.</p>
<p>This makes it easier to understand, implement, and consume those APIs. And standards matter, as they allow different teams, regardless of their technology stack, to effectively communicate about and work with the same API.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3191c4bd-690b-45e8-86bb-8b460ae434c6_1295x1490.png" alt="API Lifecycle" width="600" height="400" loading="lazy"></p>
<p>In this practical guide, I’ll want to walk you through all the important parts involved in architecting, implementing, and consuming an API using the OpenAPI standard.</p>
<p>Before we dive in, it's helpful to have a basic understanding of the following:</p>
<ul>
<li><p>The Go programming language</p>
</li>
<li><p>RESTful APIs</p>
</li>
<li><p>JSON/YAML</p>
</li>
<li><p>Basic command-line usage</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-the-openapi-specification-oas">What is the OpenAPI Specification (OAS)?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-architecting-the-api">Architecting the API</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-openapiyaml">openapi.yaml</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-paths-and-operations">Paths and Operations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-schemas">Schemas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-extensions">Extensions</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-generate-a-go-server">How to Generate a Go Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-visualize-api-docs">How to visualize API docs</a></p>
</li>
<li><p><a target="_blank" href="heading-client-code">Client Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-the-openapi-specification-oas">What is the OpenAPI Specification (OAS)?</h2>
<p>The OpenAPI Specification (OAS) provides a consistent means to carry information through each stage of the API lifecycle. It is a specification language for HTTP APIs that defines structure and syntax in a way that is not wedded to the programming language the API is created in.</p>
<p>The <a target="_blank" href="https://spec.openapis.org/">OpenAPI Specification (OAS)</a> was originally based on the Swagger 2.0 Specification from SmartBear Software. Later it was moved to the <a target="_blank" href="https://www.openapis.org/">OpenAPI Initiative (OAI)</a>, a consortium of industry experts under the Linux Foundation.</p>
<p>The main idea of OpenAPI is to be able to describe APIs in agnostic terms, decoupling them from any specific programming language. Consumers of your API specification do not need to understand the guts of your application or try to learn Lisp or Haskell if that’s what you chose to write it in. They can understand exactly what they need from your API specification, written in a simple and expressive language.</p>
<p>This simple and expressive language is called <a target="_blank" href="https://www.jetbrains.com/mps/concepts/domain-specific-languages/">DSL (domain specific language)</a>. It can be written in either JSON or YAML.</p>
<p>The latest version of OAS is <a target="_blank" href="https://spec.openapis.org/oas/latest.html">v3.1.1</a> and the specification itself is huge. There are many features and corner cases, but we will try to go through the most important ones.</p>
<h2 id="heading-architecting-the-api">Architecting the API</h2>
<p>It all starts with defining what the API should provide for its consumers and what it is for. While this stage isn't always purely technical, having a sketch of your API design in OAS when gathering requirements gives you a head start when starting the design.</p>
<p>Once the requirements are ready, it's time to open your <a target="_blank" href="https://editor.swagger.io/">OpenAPI editor</a> and collaborate with your teammates.</p>
<p>And it's important to understand that it's not only about writing the JSON/YAML spec, but actually agreeing on the API design.</p>
<p>I recommend that you follow some API design guide – <a target="_blank" href="https://cloud.google.com/apis/design">Google has</a> <a target="_blank" href="https://cloud.google.com/apis/design">one</a>, for example. This will help you avoid mixed styles (like <strong>/resourceName/{id}</strong> and <strong>/resource_name/{id}</strong>, inconsistent use of HTTP methods, or unclear resource relationships.</p>
<h3 id="heading-openapiyaml">openapi.yaml</h3>
<p>The spec of your API starts in the entrypoint document <code>openapi.yaml</code> (recommended but not required name) or <code>openapi.json</code>. I've seen very big <code>openapi.yaml</code> files (50k lines), but it's possible to split your spec into multiple parts. Just keep in mind that this may not work well for some OpenAPI tools as they expect a single file. <a target="_blank" href="https://github.com/googlemaps/openapi-specification/">Google Maps OAS</a> is a good example on how to split the schema, but also comes with a pre-processor to generate a single file.</p>
<p>There are some open source tools to bundle the OAS: <a target="_blank" href="https://github.com/APIDevTools/swagger-cli">swagger-cli</a> (archived) and <a target="_blank" href="https://github.com/Redocly/redocly-cli">redocly-cli</a> are great options.</p>
<pre><code class="lang-bash">swagger-cli bundle -o _bundle/openapi.yaml openapi.yaml
</code></pre>
<p>As I mentioned earlier, the spec is huge, but let's break it into smaller parts. For this tutorial I created a dummy "Smart Home" API. You can see the full spec and code <a target="_blank" href="https://github.com/plutov/packagemain/tree/master/oapi-example">here</a>.</p>
<p>The root object is called <a target="_blank" href="https://spec.openapis.org/oas/latest.html#openapi-object">OpenAPI Object</a> and has the following structure:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># schema version</span>
<span class="hljs-attr">openapi:</span> <span class="hljs-number">3.1</span><span class="hljs-number">.1</span>

<span class="hljs-comment"># docs</span>
<span class="hljs-attr">info:</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">Smart</span> <span class="hljs-string">Home</span> <span class="hljs-string">API</span>
  <span class="hljs-attr">description:</span> <span class="hljs-string">API</span> <span class="hljs-string">Specification</span> <span class="hljs-string">for</span> <span class="hljs-string">Smart</span> <span class="hljs-string">Home</span> <span class="hljs-string">API</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.1</span>

<span class="hljs-comment"># optional servers for public APIs</span>
<span class="hljs-attr">servers:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">"https://..."</span>

<span class="hljs-comment"># tags are used to group the endpoints</span>
<span class="hljs-attr">tags:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">device</span>
    <span class="hljs-attr">description:</span> <span class="hljs-string">Manage</span> <span class="hljs-string">devices</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">room</span>
    <span class="hljs-attr">description:</span> <span class="hljs-string">Manage</span> <span class="hljs-string">rooms</span>

<span class="hljs-comment"># endpoints go here</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-comment"># ...</span>

<span class="hljs-comment"># reusable objects such as schemas, error types, request bodies</span>
<span class="hljs-attr">components:</span>
  <span class="hljs-comment"># ...</span>

<span class="hljs-comment"># security mechanisms, should correspond to components.securitySchemes</span>
<span class="hljs-attr">security:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">apiKeyAuth:</span> []
</code></pre>
<p>We defined the skeleton of our schema, but the majority of OpenAPI schema lays in the <code>paths</code> and <code>components</code> props.</p>
<h3 id="heading-paths-and-operations">Paths and Operations</h3>
<p>Let's now add a few endpoints to our schema. The operations are grouped by paths, so you can have multiple HTTP methods on a single path – for example <code>GET /devices/{deviceId}</code> and <code>DELETE /devices/{deviceId}</code>.</p>
<p>It's a good practice to define all types (request bodies, responses, errors) in the <code>components</code> section and reference them instead of manually defining them in the <code>paths</code> section. This allows for easier re-use of entities. For example, in our API we have a type <code>Device</code> which can be used in many endpoints.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">paths:</span>

  <span class="hljs-comment"># the path has a parameter in it</span>
  <span class="hljs-string">/devices/{deviceId}:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">tags:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">device</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Get</span> <span class="hljs-string">Device</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">getDevice</span>

      <span class="hljs-attr">parameters:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">deviceId</span>
          <span class="hljs-attr">in:</span> <span class="hljs-string">path</span>
          <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
          <span class="hljs-attr">schema:</span>
            <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/ULID"</span>

      <span class="hljs-attr">responses:</span>

        <span class="hljs-attr">"200":</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Success</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/Device"</span>

        <span class="hljs-attr">"404":</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Not</span> <span class="hljs-string">Found</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-comment"># use common type for 404 errors</span>
                <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/ErrorNotFound"</span>
</code></pre>
<p>In the spec above, we defined two endpoints of our API and referenced the types which we still need to define: <code>Device</code>, <code>ErrorNotFound</code> and <code>ULID</code>. Notice that for the <code>deviceId</code> path param we also used a custom type instead of a standard string, which can be helpful in the future in case we want to change the format of our IDs (for example UUID, ULID. integer, and so on).</p>
<p>Notice that each operation has a unique <code>operationId</code>. While it's optional, it's very helpful to set one, so then it can be used on the server and client sides.</p>
<p>This is a basic configuration which you can extend further if you want to. For example, when serving this schema in Swagger, it's good to see the examples of our requests (and their variations). We can define it here in <code>responses</code> section, or directly in our <code>components.schemas</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">responses:</span>
  <span class="hljs-attr">"200":</span>
    <span class="hljs-attr">content:</span>
      <span class="hljs-attr">application/json:</span>
        <span class="hljs-attr">examples:</span>
          <span class="hljs-attr">new_device:</span>
            <span class="hljs-attr">value:</span> <span class="hljs-comment"># any value</span>
</code></pre>
<h3 id="heading-schemas">Schemas</h3>
<p><code>components</code> is an integral part of OAS, and contains the following properties:</p>
<ul>
<li><p>schemas</p>
</li>
<li><p>responses</p>
</li>
<li><p>parameters</p>
</li>
<li><p>requestBodies</p>
</li>
<li><p>headers</p>
</li>
<li><p>securitySchemes</p>
</li>
</ul>
<p>You can <a target="_blank" href="https://spec.openapis.org/oas/latest.html#components-object">see all here</a>.</p>
<p>We could define our <code>Device</code> type like this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">Device:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">id:</span>
          <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/ULID'</span>
        <span class="hljs-attr">name:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
      <span class="hljs-attr">required:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">id</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">name</span>
</code></pre>
<p>But later you may have other types that have <code>name</code> or <code>id</code> fields, so it's recommended to define them separately and combine them in the final type using <code>allOf</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">WithId:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">required:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">id</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">id:</span>
          <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/ULID"</span>

    <span class="hljs-attr">WithName:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">required:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">name</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">name:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>

    <span class="hljs-attr">Device:</span>
      <span class="hljs-attr">allOf:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/WithId"</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">$ref:</span> <span class="hljs-string">"#/components/schemas/WithName"</span>
</code></pre>
<p><code>allOf</code>, <code>oneOf</code>, and <code>anyOf</code> are very powerful techniques for modeling your OAS.</p>
<h3 id="heading-extensions">Extensions</h3>
<p>OpenAPI schemas can be extended with internal properties that do not affect the schema itself, but are useful for server or client generators. A good example is our <a target="_blank" href="https://github.com/ulid/spec">ULID</a> type for ids:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">ULID:</span>
  <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
  <span class="hljs-attr">minLength:</span> <span class="hljs-number">26</span>
  <span class="hljs-attr">maxLength:</span> <span class="hljs-number">26</span>

  <span class="hljs-comment"># example is useful for Swagger docs</span>
  <span class="hljs-attr">example:</span> <span class="hljs-string">01ARZ3NDEKTSV4RRFFQ69G5FAV</span>

  <span class="hljs-attr">x-go-type:</span> <span class="hljs-string">ulid.ULID</span>
  <span class="hljs-attr">x-go-type-import:</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">github.com/oklog/ulid/v2</span>
</code></pre>
<p>The <code>x-</code> props will be used by the Go server generator to use existing Go types for this field instead of generating a new one.</p>
<h2 id="heading-how-to-generate-a-go-server">How to Generate a Go Server</h2>
<p>We didn't go through all possible schema properties here and just covered the main ones – so if you’re not familiar with OAS, you should now have a good understanding of this standard. You can read the whole specification <a target="_blank" href="https://spec.openapis.org/oas/latest.html">here</a>. But now as our schema is ready, we can generate a Go server from it.</p>
<p>You can find the full list of generators on <a target="_blank" href="https://openapi.tools/">opeanapi.tools</a> – there are a lot of them. But the most popular one for Go servers is <a target="_blank" href="https://github.com/oapi-codegen/oapi-codegen">oapi-codegen</a>.</p>
<blockquote>
<p>oapi-codegen currently doesn’t support this OAS 3.1. <a target="_blank" href="https://github.com/oapi-codegen/oapi-codegen/issues/373">issue</a>. <a target="_blank" href="https://github.com/ogen-go/ogen/">ogen</a> does, though.</p>
</blockquote>
<p>You can install it via <code>go install</code>:</p>
<pre><code class="lang-bash">go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
</code></pre>
<p>The configuration for the <code>oapi-codegen</code> generator is straightforward. You can either provide command line arguments or specify the same arguments in a yaml configuration file. You can choose which HTTP router to use for the server, where to put the output file, and more. In our case let's use the <a target="_blank" href="https://github.com/labstack/echo">echo</a> router.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># oapi-codegen.yaml</span>

<span class="hljs-attr">package:</span> <span class="hljs-string">api</span>
<span class="hljs-attr">output:</span> <span class="hljs-string">pkg/api/api.gen.go</span>

<span class="hljs-attr">generate:</span>
  <span class="hljs-attr">strict-server:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">models:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">echo-server:</span> <span class="hljs-literal">true</span>
</code></pre>
<p>We can now generate the server code using the following command:</p>
<pre><code class="lang-bash">oapi-codegen --config=oapi-codegen.yaml openapi.yaml
</code></pre>
<p>Let's now explore the generated <code>api.gen.go</code> file.</p>
<p>Since we enabled <code>strict-server</code>, which will generate code that parses request bodies and encodes responses automatically, the interface that we need to implement is called <code>StrictServerInterface</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> StrictServerInterface <span class="hljs-keyword">interface</span> {

  <span class="hljs-comment">// List Devices</span>
  <span class="hljs-comment">// (GET /devices)</span>
  ListDevices(ctx context.Context, request ListDevicesRequestObject) (ListDevicesResponseObject, error)

  <span class="hljs-comment">// Get Device</span>
  <span class="hljs-comment">// (GET /devices/{deviceId})</span>
  GetDevice(ctx context.Context, request GetDeviceRequestObject) (GetDeviceResponseObject, error)

}
</code></pre>
<p>All our types are also generated:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> ULID = ulid.ULID

<span class="hljs-keyword">type</span> Device <span class="hljs-keyword">struct</span> {
    Id   ULID   <span class="hljs-string">`json:"id"`</span>
    Name <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>As well as code to parse the requests automatically and the Swagger definition.</p>
<h3 id="heading-implementation">Implementation</h3>
<p>What's left for us to do is to create a server using echo, implement the generated interface, and glue everything together. We can write the following code in <code>pkg/api/impl.go</code>:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> api

<span class="hljs-keyword">import</span> <span class="hljs-string">"context"</span>

<span class="hljs-keyword">type</span> Server <span class="hljs-keyword">struct</span>{}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewServer</span><span class="hljs-params">()</span> <span class="hljs-title">Server</span></span> {
    <span class="hljs-keyword">return</span> Server{}
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(Server)</span> <span class="hljs-title">ListDevices</span><span class="hljs-params">(ctx context.Context, request ListDevicesRequestObject)</span> <span class="hljs-params">(ListDevicesResponseObject, error)</span></span> {
    <span class="hljs-comment">// actual implementation</span>
    <span class="hljs-keyword">return</span> ListDevices200JSONResponse{}, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(Server)</span> <span class="hljs-title">GetDevice</span><span class="hljs-params">(ctx context.Context, request GetDeviceRequestObject)</span> <span class="hljs-params">(GetDeviceResponseObject, error)</span></span> {
    <span class="hljs-comment">// actual implementation</span>
    <span class="hljs-keyword">return</span> GetDevice200JSONResponse{}, <span class="hljs-literal">nil</span>
}
</code></pre>
<p>I skipped the implementation part and just demonstrated how to return the responses. It's quite handy that <code>oapi-codegen</code> generated all possible responses for us.</p>
<p>That leaves us to start the echo server itself. Note that we don't need to write any endpoints manually now, and all request and response parsing is handled for us. Still, we need to validate the requests inside our implementation.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"oapiexample/pkg/api"</span>

    <span class="hljs-string">"github.com/labstack/echo/v4"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    server := api.NewServer()

    e := echo.New()

    api.RegisterHandlers(e, api.NewStrictHandler(
        server,
        <span class="hljs-comment">// add middlewares here if needed</span>
        []api.StrictMiddlewareFunc{},
    ))

    e.Start(<span class="hljs-string">"127.0.0.1:8080"</span>)
}
</code></pre>
<p>Now when we run our server using <code>go run .</code>, we can curl <code>localhost:8080/devices</code> to see the response!</p>
<h3 id="heading-supported-servers">Supported servers</h3>
<p><code>oapi-codegen</code> supports many web frameworks/servers, such as Chi, Fiber, Gin as well as standard <code>net/http</code>.</p>
<h3 id="heading-how-to-visualize-api-docs">How to visualize API docs</h3>
<p>Sometimes it's handy to have Swagger docs shipped together with your API – for testing, for example, or just as public documentation. <code>oapi-codegen</code> doesn't generate the Swagger UI out of the box, but we can have a simple HTML page that has a Swagger JS which loads our OAS.</p>
<p>You can find the HTML code for our <code>pkg/api/index.html</code> <a target="_blank" href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/installation/">here</a>.</p>
<p>And then we can use <code>go:embed</code> to embed the static files and add our Swagger endpoint:</p>
<pre><code class="lang-go"><span class="hljs-comment">//go:embed pkg/api/index.html</span>
<span class="hljs-comment">//go:embed openapi.yaml</span>
<span class="hljs-keyword">var</span> swaggerUI embed.FS

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// ...</span>

    <span class="hljs-comment">// serve swagger docs</span>
    e.GET(<span class="hljs-string">"/swagger/*"</span>, echo.WrapHandler(http.StripPrefix(<span class="hljs-string">"/swagger/"</span>, http.FileServer(http.FS(swaggerUI)))))
}
</code></pre>
<p>Now we can visit <code>localhost:8080/swagger/</code> to see the Swagger UI with our OAS.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d35f8f-e1e7-4e51-9149-e180bb192fd8_1092x922.png" alt="Swagger UI" width="600" height="400" loading="lazy"></p>
<p>Tools like Postman are very popular for API documentation, and it's also possible to <a target="_blank" href="http://learning.postman.com/docs/integrations/available-integrations/working-with-openAPI/">import</a> your existing OpenAPI 3.0 and 3.1 definitions into Postman. Postman supports both YAML and JSON formats.</p>
<h3 id="heading-generate-oas-from-code">Generate OAS from code</h3>
<p>There is also a practice to generate OpenAPI schemas from code, especially in typed languages. This approach has been popular, with the main selling point being that keeping your OpenAPI schema near the code will hopefully mean that developers keep it up to date as they work on the code.</p>
<p>This is not always the case, which is one of a few reasons this practice is dying out. And I am also not a big fan, as I haven’t seen a big value in this. Anyway, you can have a look at the following projects: <a target="_blank" href="https://github.com/go-swagger/go-swagger">go-swagger</a>, <a target="_blank" href="https://github.com/swaggo/swag">swag</a>, <a target="_blank" href="https://github.com/swaggest/rest/">swaggest/rest</a>.</p>
<h2 id="heading-client-code">Client Code</h2>
<p>As mentioned earlier, OpenAPI is very powerful for collaboration between teams, and all you have to do now is to properly version your schema (see <code>info.version</code> part) and distribute it across the teams.</p>
<p>This part can be automated to some extent by packaging your OpenAPI schema and making it available. I've seen devs use Git submodules for that or GitHub actions to publish the version schemas.</p>
<p>Let's assume our client is a web application written in TypeScript, which is quite common for web APIs. Again, there are may generators available at <a target="_blank" href="https://openapi.tools/">opeanapi.tools</a> online but the most popular one is <a target="_blank" href="https://openapi-ts.dev/">openapi-typescript</a>.</p>
<p>Here's how you can generate the TypeScript code for local or remote schemas:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Local schema</span>
npx openapi-typescript openapi.yaml -o ./client/schema.d.ts

<span class="hljs-comment"># Remote schema</span>
npx openapi-typescript https://.../openapi.yaml -o ./client/schema.d.ts
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>OpenAPI is a de-facto standard for designing, implementing, and consuming REST APIs, so it's crucial to understand how it works.</p>
<p>I hope this article has provided a useful introduction to the OpenAPI Specification, as well as practical tips and examples for how to use OAS to architect, implement, and consume APIs.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/plutov/packagemain/tree/master/oapi-example">Source code</a></p>
</li>
<li><p><a target="_blank" href="https://www.openapis.org/">OpenAPI Initiative</a></p>
</li>
<li><p><a target="_blank" href="https://openapi.tools/">openapi.tools</a></p>
</li>
<li><p><a target="_blank" href="https://editor.swagger.io/">Swagger Editor</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/oapi-codegen/oapi-codegen">oapi-codegen</a></p>
</li>
<li><p><a target="_blank" href="https://packagemain.tech">Explore more articles on packagemain.tech</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a REST API Without a Server ]]>
                </title>
                <description>
                    <![CDATA[ If you're a Front-End developer and want to showcase your skills, it may be a problem if you use GitHub pages or Netlify to show your apps. Instead, you can create a REST API directly in the browser without the need of any server. With this, you can ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-rest-api-without-a-server/</link>
                <guid isPermaLink="false">66ba5ababab56b9458240035</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jakub T. Jankiewicz ]]>
                </dc:creator>
                <pubDate>Mon, 20 May 2024 10:13:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/cover-5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're a Front-End developer and want to showcase your skills, it may be a problem if you use GitHub pages or Netlify to show your apps.</p>
<p>Instead, you can create a REST API directly in the browser without the need of any server. With this, you can showcase your skills in applications that interact with a backend hosted in places where you can't access the server side.</p>
<p>Note that if you search for "API without a server" you may find articles about <a target="_blank" href="https://en.wikipedia.org/wiki/Serverless_computing">serverless</a> (which is still a kind of <a target="_blank" href="https://www.freecodecamp.org/news/web-servers-explained-by-running-a-microbrewery-d40b9824f882/">server</a>). This article is completely different and showcases a relatively new browser API. Read on if you're interested.</p>
<h2 id="heading-table-of-contents">Table of contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#what-is-service-worker">What is a Service Worker?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-register-a-service-worker">How to register a Service Worker?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-basic-http-response">How to create a basic HTTP response</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-base-project">How to create a base project</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-set-up-vite">Set up Vite</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-the-wayne-library">Use the Wayne library</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-install-the-service-worker">Install the Service Worker</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-test-on-the-web-server">Test on the Web Server</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-react-authentication">How to add React authentication</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-create-a-jwt-token">Create a JWT token</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-authentication-api">Add authentication API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-authentication-to-react">Add authentication to React</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-next-steps">Next steps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-fully-working-demo">Fully working demo</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-service-worker">What is a Service Worker?</h2>
<p>The browser API that allows you to create pure in the browser HTTP responses to HTTP requests is called a Service Worker. This API was mostly created to intercept HTTP requests originated from the browser and serve them from cache.</p>
<p>This allows you to create applications called <a target="_blank" href="https://www.freecodecamp.org/news/what-are-progressive-web-apps-pwa-guide/">PWA</a> that work when you don't have internet connection. So you can use them while on the train, where you may have unstable internet. When you're offline, the HTTP requests can be stored and sent to the real server when you get back online.</p>
<p>But this is not all what Service Workers can do. With them, you can create HTTP requests that never existed. It can intercept any HTTP requests, for example when you open an image in new tab or using AJAX (like with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch API</a>).</p>
<h2 id="heading-how-to-register-a-service-worker">How to Register a Service Worker?</h2>
<p>Service worker needs to be written in a separate file (often called <code>sw.js</code>, but you can name it whatever you want).</p>
<p>The location of that file is important. It should be located in the root of your app, often in the root of the <a target="_blank" href="https://en.wikipedia.org/wiki/Domain_name">domain</a>.</p>
<p>To register a service worker, you need to execute this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (<span class="hljs-string">'serviceWorker'</span> <span class="hljs-keyword">in</span> navigator) {
  <span class="hljs-keyword">var</span> scope = location.pathname.replace(<span class="hljs-regexp">/\/[^\/]+$/</span>, <span class="hljs-string">'/'</span>)
  navigator.serviceWorker.register(<span class="hljs-string">'sw.js'</span>, { scope })
    .then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">reg</span>) </span>{
       reg.addEventListener(<span class="hljs-string">'updatefound'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
         <span class="hljs-keyword">var</span> installingWorker = reg.installing;
         <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A new service worker is being installed:'</span>,
                     installingWorker);
       });
       <span class="hljs-comment">// registration worked</span>
       <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Registration succeeded. Scope is '</span> + reg.scope);
    }).catch(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">error</span>) </span>{
      <span class="hljs-comment">// registration failed</span>
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Registration failed with '</span> + error);
    });
}
</code></pre>
<p>This will install a service worker that can start to intercept HTTP requests.</p>
<p><strong>NOTE:</strong> The service worker works only with HTTPS and localhost.</p>
<h2 id="heading-how-to-create-a-basic-http-response">How to Create a Basic HTTP Response</h2>
<p>The API of the Service Worker is very simple – you have an event called <code>fetch</code><br>and you can respond to that event with any response:</p>
<pre><code class="lang-javascript">self.addEventListener(<span class="hljs-string">'fetch'</span>, <span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(event.request.url);
    <span class="hljs-keyword">if</span> (url.pathname === <span class="hljs-string">'/api/hello/'</span>) {
        <span class="hljs-keyword">const</span> headers = {
            <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'text/plain'</span>
        };
        <span class="hljs-keyword">const</span> msg = <span class="hljs-string">'Hello, Service Worker!'</span>
        event.respondWith(textResponse(msg, headers));
   }
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">textResponse</span>(<span class="hljs-params">string, headers</span>) </span>{
    <span class="hljs-keyword">const</span> blob = <span class="hljs-keyword">new</span> Blob([string], {
        <span class="hljs-attr">type</span>: <span class="hljs-string">'text/plain'</span>
    });
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(blob, { headers });
}
</code></pre>
<p>With this you code, you can open the URL <code>/api/hello/</code> and it will display the text <code>"Hello, Service Worker!"</code> as a text file.</p>
<p>Also, one important thing: if you want to use the Service Worker immediately after it's installed, you need to add this code:</p>
<pre><code class="lang-javascript">self.addEventListener(<span class="hljs-string">'activate'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.waitUntil(clients.claim());
});
</code></pre>
<p>Normally, the Service Worker intercepts requests only after you refresh the page. This code forces to accept requests immediately after installation.</p>
<p><strong>NOTE:</strong> With service worker, you can also intercept request that are sent to different domains. If you have your app on GitHub pages, you can intercept the requests to any domain. Because there are no checks of the domain, this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://example.com/api/hello'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.text())
</code></pre>
<p>will also return <code>Hello, Service Worker!</code>.</p>
<h2 id="heading-how-to-create-a-base-project">How to Create a Base Project</h2>
<p>You will create something more useful by creating a React project with very simple user authentication.</p>
<p>Note that this is not secure in any way, because user information and passwords will be visible in the code. But it can show that you know how to interact with an API in React.</p>
<h3 id="heading-set-up-vite">Set Up Vite</h3>
<p>First, you need to set up a simple React application with <a target="_blank" href="https://vitejs.dev/">Vite</a>.</p>
<p>To use Vite, you need to have Node.js installed. If you don't have it, you can read how to install it from <a target="_blank" href="https://www.freecodecamp.org/news/how-to-install-node-in-your-machines-macos-linux-windows/">this article</a>.</p>
<p>Then, you need to run this command from the terminal:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>I've picked name <code>auth</code>, React, and JavaScript. This is the output I've got:</p>
<pre><code class="lang-python">✔ Project name: … auth
✔ Select a framework: › React
✔ Select a variant: › JavaScript

Scaffolding project <span class="hljs-keyword">in</span> /home/kuba/auth...

Done. Now run:

  cd auth
  npm install
  npm run dev
</code></pre>
<p>Next is to modify <code>vite.config.js</code> file, so Vite will know how to build the service worker file/</p>
<p>This is the config file Vite created:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>

<span class="hljs-comment">// https://vitejs.dev/config/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [react()],
})
</code></pre>
<p>You need to modify the config file to include this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { join } <span class="hljs-keyword">from</span> <span class="hljs-string">"node:path"</span>;
<span class="hljs-keyword">import</span> { buildSync } <span class="hljs-keyword">from</span> <span class="hljs-string">"esbuild"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [
    react(),
    {
      <span class="hljs-attr">apply</span>: <span class="hljs-string">"build"</span>,
      <span class="hljs-attr">enforce</span>: <span class="hljs-string">"post"</span>,
      transformIndexHtml() {
        buildSync({
          <span class="hljs-attr">minify</span>: <span class="hljs-literal">true</span>,
          <span class="hljs-attr">bundle</span>: <span class="hljs-literal">true</span>,
          <span class="hljs-attr">entryPoints</span>: [join(process.cwd(), <span class="hljs-string">"src"</span>, <span class="hljs-string">"sw.js"</span>)],
          <span class="hljs-attr">outfile</span>: join(process.cwd(), <span class="hljs-string">"dist"</span>, <span class="hljs-string">"sw.js"</span>),
        });
      },
    },
  ]
})
</code></pre>
<p>You need to include both imports and you can replace the existing config with the one above. You can also add the code in the curly braces into a plugin array.</p>
<h3 id="heading-use-the-wayne-library">Use the Wayne library</h3>
<p>Then, you need to create a Service Worker file named <code>sw.js</code>. You will use <a target="_blank" href="https://github.com/jcubic/wayne">Wayne library</a> instead of writing the routes yourself. This will simplify the code.</p>
<p>First, you need to install Wayne:</p>
<pre><code class="lang-bash">npm install @jcubic/wayne
</code></pre>
<p>Then, you can create a file named <code>sw.js</code> (<strong>Note:</strong> you've put the <code>"src"</code> directory in the <code>vite.config.js</code> file, so you should save the file in that directory).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Wayne } <span class="hljs-keyword">from</span> <span class="hljs-string">'@jcubic/wayne'</span>;

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

app.get(<span class="hljs-string">'/api/hello/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
   res.text(<span class="hljs-string">'Hello, Service Worker!'</span>);
});
</code></pre>
<p>This code will work exactly the same as our previous example.</p>
<h3 id="heading-install-the-service-worker">Install the Service Worker</h3>
<p>Now, the last thing you need to do to set up your service worker is to register it. You could use the code that you saw earlier, but now you will use a library for this.</p>
<p>First, you need to install it:</p>
<pre><code class="lang-bash">npm install register-service-worker
</code></pre>
<p>And update <code>src/main.jsx</code> with this code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { register } <span class="hljs-keyword">from</span> <span class="hljs-string">"register-service-worker"</span>;

register(<span class="hljs-string">`./sw.js`</span>);
</code></pre>
<p>The last thing is to build the project by executing:</p>
<pre><code class="lang-bash">npm run build
</code></pre>
<p><strong>NOTE</strong>: the <code>dev</code> mode will not work with the service worker – you need to build the project.</p>
<p>The instructions setting up a Service Worker with Vite were based on <a target="_blank" href="https://dev.to/reeshee/how-to-bundle-your-custom-service-worker-in-vite-without-using-pwa-4nk">this articl</a>e.</p>
<h3 id="heading-test-on-the-web-server">Test on the Web Server</h3>
<p>To test your project you can use this command:</p>
<pre><code class="lang-bash">npx http-server -p 3000 ./dist/
</code></pre>
<p>This will create a simple HTTP server where you can test your application.</p>
<p><strong>NOTE</strong>: if you open the<code>index.html</code> file in a browser (like with drag and drop), the service worker will not work. This is because the <code>file://</code> protocol has a lot of restrictions. That's why you need a web server.</p>
<p>If you test the app in the browser by opening the URL: <code>http://127.0.0.1:3000</code>, it will run the code that registers the service worker, and you will immediately be able to access our fake HTTP endpoint: <code>http://127.0.0.1:3000/api/hello/</code>. It should display the text:</p>
<pre><code class="lang-python">Hello, Service Worker!
</code></pre>
<p><strong>NOTE</strong>: to simplify testing, you can add <code>"http-server -p 3000 ./dist/"</code> to the package.json file into <code>scripts</code>:</p>
<pre><code class="lang-json"><span class="hljs-string">"serve"</span>: <span class="hljs-string">"http-server -p 3000 ./dist/"</span>,
</code></pre>
<p>Remember that <code>package.json</code> is a JSON file, so you can't put a trailing comma if this will be the last script.</p>
<p>To make it work, you need to install the package:</p>
<pre><code class="lang-bash">npm install http-server
</code></pre>
<p>Now you can run the server with <code>npm run serve</code>.</p>
<p><strong>NOTE</strong>: if you access the URL: <code>http://127.0.0.1:3000/api/hello</code> (you can read what is 127.0.0.1 in <a target="_blank" href="https://www.freecodecamp.org/news/what-is-localhost/">this article</a>), you will get an error from <code>http-server</code>. This is because the route you created in the service worker used a trailing slash. To fix this, you can add a redirect:</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/api/hello'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
   res.redirect(<span class="hljs-number">301</span>, req.url + <span class="hljs-string">'/'</span>);
});
</code></pre>
<h2 id="heading-how-to-add-react-authentication">How to Add React Authentication</h2>
<p>Now, after you have set up everything, you can add a real authentication endpoint and connect it with your React app.</p>
<h3 id="heading-create-a-jwt-token">Create a JWT token</h3>
<p>We will use a popular JWT token for authentication. You can read more about them in <a target="_blank" href="https://www.freecodecamp.org/news/how-to-sign-and-validate-json-web-tokens/">this article</a>.</p>
<p>First, you need to install a JWT library:</p>
<pre><code class="lang-bash">npm install jose
</code></pre>
<p>Then, you need to create a new file named <code>jwt.js</code> in the <code>src</code> directory:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { SignJWT, jwtVerify } <span class="hljs-keyword">from</span> <span class="hljs-string">'jose'</span>;

<span class="hljs-keyword">const</span> secret = <span class="hljs-keyword">new</span> TextEncoder().encode(
  <span class="hljs-string">'cc7e0d44fd473002f1c42167459001140ec6389b7353f8088f4d9a95f2f596f2'</span>
);

<span class="hljs-keyword">const</span> alg = <span class="hljs-string">'HS256'</span>;

<span class="hljs-keyword">const</span> jwt = {
    <span class="hljs-attr">sign</span>: <span class="hljs-function">(<span class="hljs-params">payload</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> SignJWT(payload)
            .setProtectedHeader({ alg })
            .setIssuedAt()
            .setIssuer(<span class="hljs-string">'https://freecodecamp.org'</span>)
            .setAudience(<span class="hljs-string">'https://freecodecamp.org'</span>)
            .setExpirationTime(<span class="hljs-string">'2h'</span>)
            .sign(secret)
    },
    <span class="hljs-attr">verify</span>: <span class="hljs-keyword">async</span> (token) =&gt; {
        <span class="hljs-keyword">const</span> { payload } = <span class="hljs-keyword">await</span> jwtVerify(token, secret, {
            <span class="hljs-attr">issuer</span>: <span class="hljs-string">'https://freecodecamp.org'</span>,
            <span class="hljs-attr">audience</span>: <span class="hljs-string">'https://freecodecamp.org'</span>,
        });
        <span class="hljs-keyword">return</span> payload;
    }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> jwt;
</code></pre>
<p>This code is an <a target="_blank" href="https://www.freecodecamp.org/news/javascript-modules-beginners-guide/">ES Module</a> that uses the <a target="_blank" href="https://github.com/panva/jose"><code>jose</code> JWT token library</a> to create a new token, <code>jwt.sign</code>. It verifies that the token is correct with <code>jwt.verify</code>, and it also returns the payload, so you can extract anything you save in the token.</p>
<p>You can read more about the <code>jose</code> library from the documentation – the links to the <a target="_blank" href="https://github.com/panva/jose">docs are in the README</a>.</p>
<p><strong>NOTE</strong>: Because of the limitation of Service Worker, we can't create a proper real life authentication, where the access token is stored in a cookie (Service Worker don't allow creating cookies) and use refresh tokens to update the access token.</p>
<h3 id="heading-add-authentication-api">Add authentication API</h3>
<p>Now, you can use the previous functions to create an API endpoint:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> jwt <span class="hljs-keyword">from</span> <span class="hljs-string">'./jwt'</span>;

app.post(<span class="hljs-string">'/api/login'</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> { username, password } = <span class="hljs-keyword">await</span> req.json() ?? {};
    <span class="hljs-keyword">if</span> (username === <span class="hljs-string">'demo'</span> &amp;&amp; password === <span class="hljs-string">'demo'</span>) {
        <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> jwt.sign({ username });
        res.json({ <span class="hljs-attr">result</span>: token });
    } <span class="hljs-keyword">else</span> {
        res.json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Invalid username or password'</span> });
    }
});
</code></pre>
<p>This code will verify that the username and password are correct (both equal to <code>"demo"</code>), ⁣and create a new JWT token. If the username or password are not correct, it will return an error.</p>
<h3 id="heading-add-authentication-to-react">Add authentication to React</h3>
<p>You created a React App with Vite, so you need to use JSX to add front-end authentication logic.</p>
<p>First, you create a helper function that will send an HTTP request to the <code>/api/login</code> endpoint with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">Fetch API</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">login</span>(<span class="hljs-params">username, password</span>) </span>{
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">'/api/login'</span>, {
        <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
        <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">'Accept'</span>: <span class="hljs-string">'application/json'</span>,
            <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
        },
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
            username,
            password
        })
    }).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json());
}
</code></pre>
<p>Next, you need to create a basic form:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"user"</span>&gt;</span>username<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">id</span>=<span class="hljs-string">"user"</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">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>password<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">id</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</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>login<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>
</code></pre>
<p>And a add bit of styling:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">form</span> {
  <span class="hljs-attribute">display</span>: inline-flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">align-items</span>: flex-end;
}

<span class="hljs-selector-tag">label</span><span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">":"</span>;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100px</span>;
  <span class="hljs-attribute">display</span>: inline-block;
  <span class="hljs-attribute">text-align</span>: right;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>Next, you need an authentication function that you will add to an <code>onSubmit</code> event. ⁣<br>You will use two state variables for token and error:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [token, setToken] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">auth</span>(<span class="hljs-params">event</span>) </span>{
    event.preventDefault();

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> login(username, password);
    <span class="hljs-keyword">if</span> (res.result) {
      setToken(res.result);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (res.error) {
      setError(res.error);
    }
  }
</code></pre>
<p>To get the username and password from the form you can use refs. You can also display the form only when the token is not set:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [token, setToken] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> userRef = useRef();
  <span class="hljs-keyword">const</span> passwordRef = useRef();

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">auth</span>(<span class="hljs-params">event</span>) </span>{
    event.preventDefault();
    <span class="hljs-keyword">const</span> username = userRef.current.value;
    <span class="hljs-keyword">const</span> username = passwordRef.current.value;

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> login(username, password);
    <span class="hljs-keyword">if</span> (res.result) {
      setToken(res.result);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (res.error) {
      setError(res.error);
    }
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"card"</span>&gt;</span>
        {!token &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{auth}</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">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"user"</span>&gt;</span>username<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">id</span>=<span class="hljs-string">"user"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{userRef}/</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">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>password<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">id</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{passwordRef}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</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>login<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>
        )}
        {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"error"</span>&gt;</span>{ error }<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now you can test the App. If you type the username and password, they don't reset.</p>
<p>You can fix it by setting the ref value to an empty string at the end of the function:</p>
<pre><code class="lang-javascript">userRef.current.value = <span class="hljs-string">''</span>;
passwordRef.current.value = <span class="hljs-string">''</span>;
</code></pre>
<p>There is another error. If you put a wrong username or password, you will get an error. But then, if you type the correct password, the error is not removed. To fix this issue, you need to reset the error state when setting the token:</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">auth</span>(<span class="hljs-params">event</span>) </span>{
    event.preventDefault();
    <span class="hljs-keyword">const</span> username = userRef.current.value;
    <span class="hljs-keyword">const</span> username = passwordRef.current.value;

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> login(username, password);
    <span class="hljs-keyword">if</span> (res.result) {
      setToken(res.result);
      setError(<span class="hljs-literal">null</span>);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (res.error) {
      setError(res.error);
    }
    userRef.current.value = <span class="hljs-string">''</span>;
    passwordRef.current.value = <span class="hljs-string">''</span>;
  }
</code></pre>
<p>Next thing that you can do is to extract the username from the token. This will also verify that the token is correct in your React app. You need to use the <code>useEffect</code> hook to run the code when the token changes:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> jwt <span class="hljs-keyword">from</span> <span class="hljs-string">'./jwt'</span>;

  <span class="hljs-comment">// ...</span>
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    jwt.verify(token).then(<span class="hljs-function"><span class="hljs-params">payload</span> =&gt;</span> {
      <span class="hljs-keyword">const</span> { username } = payload;
      setUsername(username);
    }).catch(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
      setError(e.message);
    });
  }, [token]);

  <span class="hljs-comment">// ...</span>
</code></pre>
<p>If you run this code, you will get an error: <code>Compact JWS must be a string or Uint8Array</code>.</p>
<p>The reason is that the <code>useEffect</code> hook will be triggered when the token is <code>null</code>. Before you verify, you need to check if the token was set:</p>
<pre><code class="lang-javascript">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (token !== <span class="hljs-literal">null</span>) {
      jwt.verify(token).then(<span class="hljs-function"><span class="hljs-params">payload</span> =&gt;</span> {
        <span class="hljs-keyword">const</span> { username } = payload;
        setUsername(username);
      }).catch(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
        setError(e.message);
      });
    }
  }, [token]);
</code></pre>
<p>Next, you can display the username after user login:</p>
<pre><code class="lang-jsx">{token &amp;&amp; (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Welcome {username}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
)}
</code></pre>
<h2 id="heading-next-steps">Next Steps</h2>
<p>The last thing we can do is to save the token in <code>localStorage</code> and add a logout button. But this is left as an exercise to the reader.</p>
<p>You can read about <code>localStorage</code> from <a target="_blank" href="https://www.freecodecamp.org/news/use-local-storage-in-modern-applications/">this freeCodeCamp article</a>.</p>
<p>You can improve this and add more endpoints, like getting real data that you will save in a <code>sw.js</code> file. You can store the data in IndexedDB, so it will be persistent like in in a real app. Read more about IndexedDB from <a target="_blank" href="https://www.freecodecamp.org/news/how-indexeddb-works-for-beginners/">this article</a>.</p>
<p>IndexedDB doesn't have a very nice API, but there are libraries that add abstraction on top of it. My favorite is the SQL library <a target="_blank" href="https://alasql.org/">AlaSQL</a>, and <a target="_blank" href="https://github.com/jakearchibald/idb">idb</a> by <a target="_blank" href="https://jakearchibald.com/">Jake Archibald</a>.</p>
<h2 id="heading-fully-working-demo">Fully working demo</h2>
<p>The full source code is available on GitHub in the repository <a target="_blank" href="https://github.com/jcubic/react-wayne-auth">jcubic/react-wayne-auth</a>. You can test a working demo on <a target="_blank" href="https://jcubic.github.io/react-wayne-auth/">GitHub pages</a>.</p>
<p>If you like this article, you may want to follow me on Social Media: (<a target="_blank" href="https://x.com/jcubic">Twitter/X</a> and/or <a target="_blank" href="https://www.linkedin.com/in/jakubjankiewicz/">LinkedIn</a>) and you an also check my <a target="_blank" href="https://jakub.jankiewicz.org/">personal website</a>.</p>
 ]]>
                </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 Work with RESTful APIs in React ]]>
                </title>
                <description>
                    <![CDATA[ RESTful APIs are a crucial component in modern web development. They allow communication between different applications over the internet.  REST (which stands for Representational State Transfer) APIs operate on a stateless client-server architecture... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-work-with-restful-apis-in-react-simplified-steps-and-practical-examples/</link>
                <guid isPermaLink="false">66c4c3f3d788a9c53d88d2c2</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joan Ayebola ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jan 2024 19:09:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/How-to-Work-with-RESTful-APIs-in-React.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>RESTful APIs are a crucial component in modern web development. They allow communication between different applications over the internet. </p>
<p>REST (which stands for Representational State Transfer) APIs operate on a stateless client-server architecture, providing a standardized way to create, read, update, and delete resources.</p>
<p>Integrating RESTful APIs with React enhances the functionality of your web applications by enabling them to fetch and update data dynamically. This integration facilitates a seamless user experience, ensuring that the application remains responsive and up-to-date.</p>
<p>In this article, we will delve into the fundamentals of RESTful APIs and guide you through the process of working with them in React. From setting up a new React project to handling CRUD operations and implementing authentication, you'll gain a comprehensive understanding of integrating APIs into your React applications</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into this guide, ensure you have some familiarity with the following:</p>
<p><strong>Conceptual Knowledge:</strong></p>
<ul>
<li>JavaScript fundamentals (variables, functions, arrays, objects)</li>
<li>Basic understanding of web development with HTML and CSS</li>
<li>Knowledge of RESTful APIs and their operations (GET, POST, PUT, DELETE)</li>
</ul>
<p><strong>Technical Skills:</strong></p>
<ul>
<li>Ability to use a command-line interface (terminal)</li>
<li>Basic understanding of Node.js and npm package manager</li>
</ul>
<p><strong>Tools:</strong></p>
<ul>
<li>Text editor or IDE for code development</li>
<li>Web browser</li>
</ul>
<p>Having these prerequisites will allow you to follow the guide and build your understanding of integrating RESTful APIs with React applications. If you're unfamiliar with any of these concepts, there are plenty of resources available online to help you get up to speed.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><strong><a class="post-section-overview" href="#understanding-restful-apis">Understanding RESTful APIs</a></strong></p>
</li>
<li><p>1.1 <a class="post-section-overview" href="#heading-11-what-is-rest">What is REST?</a></p>
</li>
<li>1.2 <a class="post-section-overview" href="#heading-12-key-principles-of-rest">Key Principles of REST</a></li>
<li>1.3 <a class="post-section-overview" href="#heading-13-anatomy-of-a-restful-api">Anatomy of a RESTful API</a></li>
<li><p>1.4 <a class="post-section-overview" href="#heading-14-restful-api-endpoints">RESTful API Endpoints</a></p>
</li>
<li><p><strong><a class="post-section-overview" href="#heading-2-how-to-set-up-a-react-project">How to Set Up a React Project</a></strong></p>
</li>
<li><p>2.1 <a class="post-section-overview" href="#2-1-creating-a-react-app">Creating a React App</a></p>
</li>
<li>2.2 <a class="post-section-overview" href="#heading-22-installing-dependencies">Installing Dependencies</a></li>
<li><p>2.3 <a class="post-section-overview" href="#heading-23-project-structure-overview">Project Structure Overview</a></p>
</li>
<li><p><strong>  <a class="post-section-overview" href="#heading-3-how-to-make-api-requests-in-react">How to Make API Requests in React</a></strong></p>
</li>
<li><p>3.1 <a class="post-section-overview" href="#heading-31-the-fetch-api">The Fetch API</a></p>
</li>
<li>3.2 <a class="post-section-overview" href="#heading-32-making-get-requests">Making GET Requests</a></li>
<li>3.3 <a class="post-section-overview" href="#heading-33-handling-asynchronous-operations-with-asyncawait">Handling Asynchronous Operations with <code>async/await</code></a></li>
<li><p>3.4 <a class="post-section-overview" href="#heading-34-error-handling">Error Handling</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-display-api-data-in-react-components">How to Display API Data in React Components</a></p>
</li>
<li><p>4.1 <a class="post-section-overview" href="#heading-41-state-and-props-in-react">State and Props in React</a></p>
</li>
<li>4.2 <a class="post-section-overview" href="#heading-42-updating-state-with-fetched-data">Updating State with Fetched Data</a></li>
<li>4.3 <a class="post-section-overview" href="#heading-43-rendering-data-dynamically">Rendering Data Dynamically</a></li>
<li><p>4.4 <a class="post-section-overview" href="#heading-44-loading-states-and-error-handling">Loading States and Error Handling</a></p>
</li>
<li><p><strong><a class="post-section-overview" href="#crud-operations-with-restful-apis">CRUD Operations with RESTful APIs</a></strong></p>
</li>
<li><p>5.1 <a class="post-section-overview" href="#heading-51-creating-data-post-requests">Creating Data (POST Requests)</a></p>
</li>
<li>5.2 <a class="post-section-overview" href="#heading-52-reading-data-get-requests">Reading Data (GET Requests)</a></li>
<li>5.3 <a class="post-section-overview" href="#heading-53-updating-data-putpatch-requests">Updating Data (PUT/PATCH Requests)</a></li>
<li><p>5.4 <a class="post-section-overview" href="#heading-54-deleting-data-delete-requests">Deleting Data (DELETE Requests)</a></p>
</li>
<li><p><strong>   <a class="post-section-overview" href="#how-to-handle-forms-and-user-input">How to Handle Forms and User Input</a></strong></p>
</li>
<li><p>6.1 <a class="post-section-overview" href="#heading-61-controlled-components">Controlled Components</a></p>
</li>
<li>6.2 <a class="post-section-overview" href="#heading-62-form-submission-and-handling">Form Submission and Handling</a></li>
<li>6.3 <a class="post-section-overview" href="#heading-63-sending-data-to-the-api">Sending Data to the API</a></li>
<li><p>6.4 <a class="post-section-overview" href="#heading-64-validation-and-error-messages">Validation and Error Messages</a></p>
</li>
<li><p><strong>  <a class="post-section-overview" href="#authentication-and-authorization">Authentication and Authorization</a></strong></p>
</li>
<li><p>7.1 <a class="post-section-overview" href="#heading-71-understanding-authentication-vs-authorization">Understanding Authentication vs Authorization</a></p>
</li>
<li>7.2 <a class="post-section-overview" href="#heading-72-implementing-token-based-authentication">Implementing Token-based Authentication</a></li>
<li><p>7.3 <a class="post-section-overview" href="#heading-73-securing-api-requests">Securing API Requests</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-optimize-performance">How to Optimize Performance</a></p>
</li>
<li><p>8.1 <a class="post-section-overview" href="#heading-81-caching-api-responses">Caching API Responses</a></p>
</li>
<li>8.2 <a class="post-section-overview" href="#heading-82-lazy-loading-and-pagination">Lazy Loading and Pagination</a></li>
<li><p>8.3 <a class="post-section-overview" href="#heading-83-optimizing-re-rendering-with-reactmemo">Optimizing Re-rendering with <code>React.memo</code></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-9-how-to-test-your-react-app-with-restful-apis">How to Test Your React App with RESTful APIs</a></p>
</li>
<li><p>9.1 <a class="post-section-overview" href="#heading-91-unit-testing-components">Unit Testing Components</a></p>
</li>
<li>9.2 <a class="post-section-overview" href="#heading-92-mocking-api-requests-for-testing">Mocking API Requests for Testing</a></li>
<li><p>9.3 <a class="post-section-overview" href="#heading-93-end-to-end-testing-with-tools-like-cypress">End-to-End Testing with Tools like Cypress</a></p>
</li>
<li><p><strong>   <a class="post-section-overview" href="#heading-10-best-practices-and-tips">Best Practices and Tips</a></strong></p>
</li>
<li><p>10.1 <a class="post-section-overview" href="#heading-101-code-organization">Code Organization</a></p>
</li>
<li>10.2 <a class="post-section-overview" href="#heading-102-error-handling-strategies">Error Handling Strategies</a></li>
<li>10.3 <a class="post-section-overview" href="#heading-103-securing-api-keys">Securing API Keys</a></li>
<li><p>10.4 <a class="post-section-overview" href="#heading-104-monitoring-and-analytics">Monitoring and Analytics</a></p>
</li>
<li><p><strong>   <a class="post-section-overview" href="#heading-conclusion">Conclusion</a></strong></p>
</li>
</ol>
<h2 id="heading-1-understanding-restful-apis">1. Understanding RESTful APIs</h2>
<h3 id="heading-11-what-is-rest">1.1 What is REST?</h3>
<p>REST (Representational State Transfer) is an architectural style that defines a set of constraints to be used when creating web services. It is not a protocol but a set of principles that dictate how web services should behave. </p>
<p>At its core, REST relies on a stateless client-server communication model, which means that each request from a client contains all the information needed to understand and process the request.</p>
<h3 id="heading-12-key-principles-of-rest">1.2 Key Principles of REST</h3>
<p>RESTful APIs follow several key principles, including statelessness, uniform interface, and resource-based interactions. </p>
<p>Statelessness ensures that each request from a client to a server is independent, and the server does not store any information about the client's state between requests. The uniform interface principle defines a standardized way to interact with resources, promoting simplicity and consistency.</p>
<h3 id="heading-13-anatomy-of-a-restful-api">1.3 Anatomy of a RESTful API</h3>
<p>A RESTful API consists of resources, each identified by a unique URI (Uniform Resource Identifier). These resources can be manipulated using standard HTTP methods such as GET, POST, PUT, PATCH, and DELETE. The API responses typically include data in a format like JSON (JavaScript Object Notation) or XML (eXtensible Markup Language).</p>
<h3 id="heading-14-restful-api-endpoints">1.4 RESTful API Endpoints</h3>
<p>Endpoints are specific URLs that represent the resources exposed by a RESTful API. For example, a simple blog API might have endpoints like <code>/posts</code> to retrieve all blog posts and <code>/posts/{id}</code> to retrieve a specific post by its unique identifier. </p>
<p>Understanding these endpoints is crucial when working with RESTful APIs in React, as they define the data you can access and manipulate.</p>
<h2 id="heading-2-how-to-set-up-a-react-project">2. How to Set Up a React Project</h2>
<h3 id="heading-21-creating-a-react-app">2.1 Creating a React App:</h3>
<p>There are multiple ways to set up a React project. For beginners, a popular option is Create React App (CRA). It provides a pre-configured template with everything you need to get started quickly and easily. </p>
<p>But while CRA remains a viable option, it's worth noting that some limitations exist, such as larger bundle sizes and slower hot module replacement (HMR). The React team actually doesn't recommend its use anymore, as they won't be maintaining it as much moving forward.</p>
<p>For a more modern and performant development experience, you can consider tools like Vite. Vite boasts faster HMR speeds, smaller production builds, and built-in support for modern JavaScript features. Although requiring slightly more initial setup, its flexibility and performance benefits might be compelling for experienced developers.</p>
<h4 id="heading-using-create-react-app-cra">Using Create React App (CRA)</h4>
<p>This option is ideal for beginners or those seeking a straightforward setup. Simply install Node.js and run the following command in your terminal.</p>
<pre><code>npx create-react-app my-app
</code></pre><p>Replace <code>my-app</code> with your desired project name. Follow the instructions to navigate to the project directory and start the development server using <code>npm start</code>. You'll find the source code in the <code>src</code> folder, ready for you to customize and build your React app.</p>
<h4 id="heading-using-vite">Using Vite</h4>
<p>While beyond the scope of this quick guide, using Vite offers several advantages as mentioned previously. If you're interested in exploring this route, refer to the extensive documentation and tutorials available on the Vite website (<a target="_blank" href="https://vitejs.dev/">https://vitejs.dev/</a>).</p>
<h3 id="heading-22-installing-dependencies">2.2 Installing Dependencies</h3>
<p>To make API requests and handle asynchronous operations in React, you'll need to install the <code>axios</code> library. Axios is a popular JavaScript library for making HTTP requests.</p>
<pre><code class="lang-bash">npm install axios
</code></pre>
<h3 id="heading-23-project-structure-overview">2.3 Project Structure Overview</h3>
<p>The default project structure created by <code>create-react-app</code> is well-organized, with important files and folders like <code>src</code>, <code>public</code>, and <code>node_modules</code>. In the <code>src</code> folder, you'll find the main React components and other files related to your application.</p>
<h2 id="heading-3-how-to-make-api-requests-in-react">3. How to Make API Requests in React</h2>
<h3 id="heading-31-the-fetch-api">3.1 The Fetch API</h3>
<p>The Fetch API is a modern interface for making HTTP requests in the browser. It provides a more powerful and flexible way to handle network requests compared to older techniques like XMLHttpRequest.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/ApiExample.js</span>

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

<span class="hljs-keyword">const</span> ApiExample = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/posts'</span>);
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
        setData(result);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>API Data<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {data.map((item) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ApiExample;
</code></pre>
<p>In this example, the <code>useEffect</code> hook is used to fetch data when the component mounts. The <code>fetch</code> function is used to make a GET request to the specified API endpoint (<code>'https://api.example.com/posts'</code>), and the response is converted to JSON using <code>response.json()</code>.</p>
<h3 id="heading-32-making-get-requests">3.2 Making GET Requests</h3>
<p>When working with RESTful APIs, GET requests are the most common. They retrieve data from the server without modifying it. Let's enhance our example to include query parameters and handle different aspects of the GET request.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/ApiExample.js</span>

<span class="hljs-comment">// ... (previous imports)</span>

<span class="hljs-keyword">const</span> ApiExample = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState

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

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Simulating a delay to show loading state</span>
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-keyword">async</span> () =&gt; {
          <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/posts?userId=1'</span>);
          <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
          setData(result);
          setLoading(<span class="hljs-literal">false</span>);
        }, <span class="hljs-number">1000</span>);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
        setLoading(<span class="hljs-literal">false</span>);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>API Data<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {loading ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {data.map((item) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ApiExample;
</code></pre>
<p>In this example, a loading state is introduced to provide feedback to users while the data is being fetched. The <code>loading</code> state is set to <code>true</code> initially and changed to <code>false</code> once the data is fetched.</p>
<h3 id="heading-33-handling-asynchronous-operations-with-asyncawait">3.3 Handling Asynchronous Operations with <code>async/await</code></h3>
<p>The use of <code>async/await</code> syntax makes asynchronous code more readable and easier to work with. It allows you to write asynchronous code that looks and behaves similar to synchronous code.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/ApiExample.js</span>

<span class="hljs-comment">// ... (previous imports)</span>

<span class="hljs-keyword">const</span> ApiExample = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/posts?userId=1'</span>);
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
        setData(result);
        setLoading(<span class="hljs-literal">false</span>);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
        setLoading(<span class="hljs-literal">false</span>);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>API Data<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {loading ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {data.map((item) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ApiExample;
</code></pre>
<p>Here, the <code>fetchData</code> function is declared as an asynchronous function using the <code>async</code> keyword. This allows the use of <code>await</code> inside the function, making the asynchronous code more straightforward and maintaining a clean and readable structure.</p>
<h3 id="heading-34-error-handling">3.4 Error Handling</h3>
<p>It's essential to handle errors gracefully when making API requests. In the previous examples, we introduced a basic error handling mechanism using <code>try/catch</code> blocks. Let's expand on this to provide more detailed error messages.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/ApiExample.js</span>

<span class="hljs-comment">// ... (previous imports)</span>

<span class="hljs-keyword">const</span> ApiExample = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/posts?userId=1'</span>);

        <span class="hljs-keyword">if</span> (!response.ok) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! Status: <span class="hljs-subst">${response.status}</span>`</span>);
        }

        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
        setData(result);
        setLoading(<span class="hljs-literal">false</span>);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
        setError(<span class="hljs-string">'An error occurred while fetching the data. Please try again later.'</span>);
        setLoading(<span class="hljs-literal">false</span>);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>API Data<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {loading ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ) : error ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{error}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
          {data.map((item) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ApiExample;
</code></pre>
<p>In this example, the <code>response.ok</code> property is checked to determine if the HTTP request was successful. If not, an error is thrown with information about the HTTP status. Additionally, a more user-friendly error message is set in the <code>error</code> state, and it's displayed in the component.</p>
<h2 id="heading-4-how-to-display-api-data-in-react-components">4. How to Display API Data in React Components</h2>
<h3 id="heading-41-state-and-props-in-react">4.1 State and Props in React</h3>
<p>In React, components manage their internal state, allowing them to dynamically update and re-render based on changes. Props, on the other hand, are used to pass data from parent to child components. </p>
<p>Let's understand how to use state and props to display API data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> DisplayData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [apiData, setApiData] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>);
        setApiData(response.data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>API Data Display<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      {apiData ? (
        // Render your component using the fetched data
        <span class="hljs-tag">&lt;<span class="hljs-name">MyComponent</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{apiData}</span> /&gt;</span>
      ) : (
        // Render a loading state or placeholder
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> MyComponent = <span class="hljs-function">(<span class="hljs-params">{ data }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      {/* Render other components based on data */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DisplayData;
</code></pre>
<h3 id="heading-42-updating-state-with-fetched-data">4.2 Updating State with Fetched Data</h3>
<p>When the data is successfully fetched from the API, we update the component's state using <code>setApiData(response.data)</code>. This triggers a re-render, ensuring the UI reflects the latest information.</p>
<h3 id="heading-43-rendering-data-dynamically">4.3 Rendering Data Dynamically</h3>
<p>Passing data as props allows components to dynamically render content. In the example, the <code>MyComponent</code> receives data as a prop and renders content based on that data.</p>
<h3 id="heading-44-loading-states-and-error-handling">4.4 Loading States and Error Handling</h3>
<p>Displaying a loading state (<code>&lt;p&gt;Loading...&lt;/p&gt;</code>) while waiting for API data ensures a better user experience. Additionally, we've included error handling to catch and log any issues that may arise during the API request.</p>
<h2 id="heading-5-crud-operations-with-restful-apis">5. CRUD Operations with RESTful APIs</h2>
<h3 id="heading-51-creating-data-post-requests">5.1 Creating Data (POST Requests)</h3>
<p>Creating data involves making a POST request to the API. Let's implement a simple form for adding new items.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> CreateData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [newData, setNewData] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleCreate = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'https://api.example.com/data'</span>, { newData });
      alert(<span class="hljs-string">'Data created successfully!'</span>);
      <span class="hljs-comment">// Optionally, fetch and update the displayed data</span>
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error creating data:'</span>, error);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Create New Data<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">value</span>=<span class="hljs-string">{newData}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNewData(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleCreate}</span>&gt;</span>Create<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CreateData;
</code></pre>
<p>In this example, we capture user input with the <code>useState</code> hook and send a POST request to the API when the "Create" button is clicked.</p>
<h3 id="heading-52-reading-data-get-requests">5.2 Reading Data (GET Requests)</h3>
<p>Reading data involves making GET requests to retrieve information from the API. We've already covered this in the previous section on displaying API data.</p>
<h3 id="heading-53-updating-data-putpatch-requests">5.3 Updating Data (PUT/PATCH Requests)</h3>
<p>Updating data requires sending a PUT or PATCH request to the API with the modified data. Let's create an example for updating existing data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> UpdateData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [updatedData, setUpdatedData] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleUpdate = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.put(<span class="hljs-string">'https://api.example.com/data/1'</span>, { updatedData });
      alert(<span class="hljs-string">'Data updated successfully!'</span>);
      <span class="hljs-comment">// Optionally, fetch and update the displayed data</span>
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error updating data:'</span>, error);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Update Data<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">value</span>=<span class="hljs-string">{updatedData}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUpdatedData(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleUpdate}</span>&gt;</span>Update<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UpdateData;
</code></pre>
<p>In this example, we capture the updated data and send a PUT request to the API endpoint for the specific item.</p>
<h3 id="heading-54-deleting-data-delete-requests">5.4 Deleting Data (DELETE Requests)</h3>
<p>Deleting data involves making a DELETE request to the API. Here's an example of how to implement a delete functionality.</p>
<pre><code class="lang-jsx"><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> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> DeleteData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> handleDelete = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">'https://api.example.com/data/1'</span>);
      alert(<span class="hljs-string">'Data deleted successfully!'</span>);
      <span class="hljs-comment">// Optionally, fetch and update the displayed data</span>
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error deleting data:'</span>, error);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Delete Data<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDelete}</span>&gt;</span>Delete<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DeleteData;
</code></pre>
<p>In this example, clicking the "Delete" button triggers a DELETE request to the API, removing the specified item.</p>
<h2 id="heading-6-how-to-handle-forms-and-user-input">6. How to Handle Forms and User Input</h2>
<h3 id="heading-61-controlled-components">6.1 Controlled Components</h3>
<p>React's controlled components allow us to handle form input dynamically. The value of the input is controlled by the component's state.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ControlledComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Controlled Component<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">value</span>=<span class="hljs-string">{inputValue}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInputValue(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Input Value: {inputValue}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ControlledComponent;
</code></pre>
<h3 id="heading-62-form-submission-and-handling">6.2 Form Submission and Handling</h3>
<p>Forms in React can be submitted by handling the <code>onSubmit</code> event. Let's create a simple form submission example.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> FormSubmission = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [formData, setFormData] = useState({
    <span class="hljs-attr">username</span>: <span class="hljs-string">''</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,
  });

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

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-comment">// Perform form submission logic, e.g., send data to API</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Form Submission<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Username:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.username}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleInputChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Password:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"

password"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.password}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleInputChange}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<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></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> FormSubmission;
</code></pre>
<p>In this example, the <code>handleInputChange</code> function updates the form data in the component's state, and the <code>handleSubmit</code> function prevents the default form submission and allows you to perform custom logic, such as sending data to an API.</p>
<h3 id="heading-63-sending-data-to-the-api">6.3 Sending Data to the API</h3>
<p>To send data to the API, integrate the form submission logic with your HTTP request code. Use the appropriate HTTP method (for example, POST) to create new data.</p>
<h3 id="heading-64-validation-and-error-messages">6.4 Validation and Error Messages</h3>
<p>Implementing form validation is crucial for ensuring data integrity. You can use conditional rendering to display error messages based on validation rules.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> FormValidation = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-string">''</span>);

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

    <span class="hljs-keyword">if</span> (!username || !password) {
      setError(<span class="hljs-string">'Username and password are required.'</span>);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Perform form submission logic, e.g., send data to API</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Form Validation<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> '<span class="hljs-attr">red</span>' }}&gt;</span>{error}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Username:
          <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">value</span>=<span class="hljs-string">{username}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          Password:
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<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></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> FormValidation;
</code></pre>
<p>In this example, the <code>error</code> state is used to display an error message when form validation fails.</p>
<h2 id="heading-7-authentication-and-authorization">7. Authentication and Authorization</h2>
<h3 id="heading-71-understanding-authentication-vs-authorization">7.1 Understanding Authentication vs Authorization</h3>
<p>Authentication verifies the identity of a user, while authorization determines what actions a user is allowed to perform. Token-based authentication is commonly used for securing APIs.</p>
<h3 id="heading-72-implementing-token-based-authentication">7.2 Implementing Token-based Authentication</h3>
<p>To implement token-based authentication, users typically log in to obtain an access token, which is then sent with each API request for authorization.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> Authentication = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [token, setToken] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleLogin = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'https://api.example.com/login'</span>, {
        username,
        password,
      });

      setToken(response.data.token);
      <span class="hljs-comment">// Save the token securely (e.g., in local storage)</span>
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Login failed:'</span>, error);
    }
  };

  <span class="hljs-keyword">const</span> handleLogout = <span class="hljs-function">() =&gt;</span> {
    setToken(<span class="hljs-string">''</span>);
    <span class="hljs-comment">// Clear the saved token</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Token-based Authentication<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      {token ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLogout}</span>&gt;</span>Logout<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">label</span>&gt;</span>
            Username:
            <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">value</span>=<span class="hljs-string">{username}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)}
            /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
            Password:
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)}
            /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLogin}</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Authentication;
</code></pre>
<p>In this example, the <code>handleLogin</code> function sends a POST request with the user's credentials, and upon success, the access token is stored in the component's state.</p>
<h3 id="heading-73-securing-api-requests">7.3 Securing API Requests</h3>
<p>To secure API requests, include the access token in the request headers. Axios provides an <code>Authorization</code> header for this purpose.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>, {
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span>,
      },
    });
    <span class="hljs-comment">// Handle the response</span>
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
  }
};
</code></pre>
<p>Include this header in all requests that require authentication.</p>
<h2 id="heading-8-how-to-optimize-performance">8. How to Optimize Performance</h2>
<h3 id="heading-81-caching-api-responses">8.1 Caching API Responses</h3>
<p>Caching API responses can significantly improve performance. Store fetched data in a state variable or a global state management solution like Redux to avoid unnecessary API calls.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [cachedData, setCachedData] = useState(<span class="hljs-literal">null</span>);

<span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">if</span> (cachedData) {
      <span class="hljs-comment">// Use cached data if available</span>
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/data'</span>);
    setCachedData(response.data);
    <span class="hljs-comment">// Handle the response</span>
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error);
  }
};
</code></pre>
<h3 id="heading-82-lazy-loading-and-pagination">8.2 Lazy Loading and Pagination</h3>
<p>You can implement <a target="_blank" href="https://www.freecodecamp.org/news/how-lazy-loading-works-in-web-development/">lazy loading</a> and pagination to optimize the rendering of large datasets. Fetch only the data needed for the current view and load additional data as the user scrolls or navigates.</p>
<h3 id="heading-83-optimizing-re-rendering-with-reactmemo">8.3 Optimizing Re-rendering with React.memo</h3>
<p>React.memo is a higher-order component that memoizes functional components, preventing unnecessary re-renders if the component's props haven't changed.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { memo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> MemoizedComponent = memo(<span class="hljs-function">(<span class="hljs-params">{ data }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      {/* Render other components based on data */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MemoizedComponent;
</code></pre>
<p>Wrap components with <code>React.memo</code> to optimize rendering performance.</p>
<h2 id="heading-9-how-to-test-your-react-app-with-restful-apis">9. How to Test Your React App with RESTful APIs</h2>
<p>Testing is a crucial part of the development process, ensuring that your application works as expected and remains robust even as it evolves. </p>
<p>In this section, we'll explore different aspects of testing in a React application that interacts with RESTful APIs.</p>
<h3 id="heading-91-unit-testing-components">9.1 Unit Testing Components</h3>
<p>Unit testing is focused on testing individual units of code in isolation. For React components, this involves testing the component's behavior, rendering, and interactions. We'll use the popular testing library <code>@testing-library/react</code> for our examples.</p>
<p>Let's consider a simple React component that fetches and displays data from a RESTful API:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/UserProfile.js</span>

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

<span class="hljs-keyword">const</span> UserProfile = <span class="hljs-function">(<span class="hljs-params">{ userId }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchUser = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">`https://api.example.com/users/<span class="hljs-subst">${userId}</span>`</span>);
        setUser(response.data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching user data:'</span>, error);
      }
    };

    fetchUser();
  }, [userId]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {user ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Email: {user.email}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading user data...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserProfile;
</code></pre>
<p>Now, let's create a unit test for this component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/UserProfile.test.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> userEvent <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/user-event'</span>;
<span class="hljs-keyword">import</span> UserProfile <span class="hljs-keyword">from</span> <span class="hljs-string">'./UserProfile'</span>;

test(<span class="hljs-string">'renders user profile data'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// Mocking Axios for unit testing</span>
  jest.mock(<span class="hljs-string">'axios'</span>);
  <span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
  axios.get.mockResolvedValue({ <span class="hljs-attr">data</span>: { <span class="hljs-attr">name</span>: <span class="hljs-string">'John Doe'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'john@example.com'</span> } });

  <span class="hljs-comment">// Render the component with a mocked userId</span>
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserProfile</span> <span class="hljs-attr">userId</span>=<span class="hljs-string">{1}</span> /&gt;</span></span>);

  <span class="hljs-comment">// Check if the loading state is displayed initially</span>
  expect(screen.getByText(<span class="hljs-string">'Loading user data...'</span>)).toBeInTheDocument();

  <span class="hljs-comment">// Wait for the component to render with fetched data</span>
  <span class="hljs-keyword">const</span> nameElement = <span class="hljs-keyword">await</span> screen.findByText(<span class="hljs-string">'John Doe'</span>);
  <span class="hljs-keyword">const</span> emailElement = screen.getByText(<span class="hljs-string">'Email: john@example.com'</span>);

  <span class="hljs-comment">// Check if the user data is displayed correctly</span>
  expect(nameElement).toBeInTheDocument();
  expect(emailElement).toBeInTheDocument();
});
</code></pre>
<p>This unit test uses Jest and <code>@testing-library/react</code> to ensure that the <code>UserProfile</code> component renders the user data correctly. We mock the Axios library to simulate a successful API response. This way, the test focuses on the component's behavior without making actual network requests.</p>
<h3 id="heading-92-mocking-api-requests-for-testing">9.2 Mocking API Requests for Testing</h3>
<p>Mocking API requests is essential to isolate components and test their logic without relying on actual network communication. In the previous example, we used Jest's <code>jest.mock</code> to mock the Axios library.</p>
<p>Here's another example with a more complex component that makes multiple API requests:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/PostList.js</span>

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

<span class="hljs-keyword">const</span> PostList = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchPosts = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://api.example.com/posts'</span>);
        setPosts(response.data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching posts:'</span>, error);
      }
    };

    fetchPosts();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Posts<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {posts.map((post) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PostList;
</code></pre>
<p>Now, let's create a test for this component, mocking the API requests:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/PostList.test.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> PostList <span class="hljs-keyword">from</span> <span class="hljs-string">'./PostList'</span>;

test(<span class="hljs-string">'renders a list of posts'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// Mocking Axios for unit testing</span>
  jest.mock(<span class="hljs-string">'axios'</span>);
  axios.get.mockResolvedValue({ <span class="hljs-attr">data</span>: [{ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Post 1'</span> }, { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'Post 2'</span> }] });

  <span class="hljs-comment">// Render the component</span>
  render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">PostList</span> /&gt;</span></span>);

  <span class="hljs-comment">// Wait for the component to render with fetched data</span>
  <span class="hljs-keyword">const</span> post1Element = <span class="hljs-keyword">await</span> screen.findByText(<span class="hljs-string">'Post 1'</span>);
  <span class="hljs-keyword">const</span> post2Element = screen.getByText(<span class="hljs-string">'Post 2'</span>);

  <span class="hljs-comment">// Check if the posts are displayed correctly</span>
  expect(post1Element).toBeInTheDocument();
  expect(post2Element).toBeInTheDocument();
});
</code></pre>
<p>In this test, we mock the Axios library to simulate a successful API response containing an array of posts. The test verifies that the <code>PostList</code> component renders the expected posts.</p>
<h3 id="heading-93-end-to-end-testing-with-tools-like-cypress">9.3 End-to-End Testing with Tools like Cypress</h3>
<p>End-to-End (E2E) testing ensures that your entire application works seamlessly, including interactions between different components. Cypress is a powerful E2E testing tool for web applications, providing a simple API for writing tests.</p>
<p>Let's create a simple Cypress test to ensure that our React application interacts correctly with a RESTful API:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// cypress/integration/api_integration_spec.js</span>

describe(<span class="hljs-string">'API Integration Tests'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'successfully fetches user data from the API'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.intercept(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'https://api.example.com/users/1'</span>, { <span class="hljs-attr">fixture</span>: <span class="hljs-string">'user.json'</span> });

    cy.visit(<span class="hljs-string">'/user-profile/1'</span>);

    cy.get(<span class="hljs-string">'h2'</span>).should(<span class="hljs-string">'contain.text'</span>, <span class="hljs-string">'John Doe'</span>);
    cy.get(<span class="hljs-string">'p'</span>).should(<span class="hljs-string">'contain.text'</span>, <span class="hljs-string">'Email: john@example.com'</span>);
  });

  it(<span class="hljs-string">'successfully fetches and displays posts from the API'</span>, <span class="hljs-function">() =&gt;</span> {
    cy.intercept(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'https://api.example.com/posts'</span>, { <span class="hljs-attr">fixture</span>: <span class="hljs-string">'posts.json'</span> });

    cy.visit(<span class="hljs-string">'/post-list'</span>);

    cy.get(<span class="hljs-string">'li'</span>).should(<span class="hljs-string">'have.length'</span>, <span class="hljs-number">2</span>);
    cy.get(<span class="hljs-string">'li'</span>).first().should(<span class="hljs-string">'contain.text'</span>, <span class="hljs-string">'Post 1'</span>);
    cy.get(<span class="hljs-string">'li'</span>).last().should(<span class="hljs-string">'contain.text'</span>, <span class="hljs-string">'Post 2'</span>);
  });
});
</code></pre>
<p>In this Cypress test, we use the <code>cy.intercept</code> command to intercept API requests and respond with predefined fixtures (<code>user.json</code> and <code>posts.json</code>). The test then visits different routes of the application and asserts that the expected data is rendered.</p>
<p>To run Cypress tests, ensure you have Cypress installed:</p>
<pre><code class="lang-bash">npm install cypress --save-dev
</code></pre>
<p>And add a script to your <code>package.json</code>:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
  <span class="hljs-attr">"cypress:open"</span>: <span class="hljs-string">"cypress open"</span>
}
</code></pre>
<p>Run Cypress using:</p>
<pre><code class="lang-bash">npm run cypress:open
</code></pre>
<p>These end-to-end tests help ensure that your entire application, including the interactions with RESTful APIs, functions correctly.</p>
<h2 id="heading-10-best-practices-and-tips">10. Best Practices and Tips</h2>
<p>After understanding how to work with RESTful APIs in React and testing your application, it's crucial to adopt best practices for maintaining a clean and efficient codebase. Here are some tips to enhance your development workflow:</p>
<h3 id="heading-101-code-organization">10.1 Code Organization</h3>
<p>Organizing your code in a structured and consistent manner improves readability and maintainability. Consider the following guidelines:</p>
<p><strong>Separation of Concerns</strong>: Divide your application into components, services, and utilities to separate logic and responsibilities.</p>
<p><strong>Folder Structure</strong>: Adopt a logical folder structure based on features or modules. For example:</p>
<pre><code>src/
|-- components/
|-- services/
|-- utils/
|-- pages/
|-- ...
</code></pre><p><strong>Naming Conventions</strong>: Use meaningful names for files, components, and variables to make your code self-explanatory.</p>
<h3 id="heading-102-error-handling-strategies">10.2 Error Handling Strategies</h3>
<p>Effective error handling ensures that your application gracefully handles unexpected situations. Consider the following strategies:</p>
<p><strong>Global Error Boundary</strong>: Implement a global error boundary in your application to catch and handle errors at the top level.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/ErrorBoundary.js</span>

<span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ErrorBoundary</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  state = { <span class="hljs-attr">hasError</span>: <span class="hljs-literal">false</span> };

  <span class="hljs-keyword">static</span> getDerivedStateFromError(error) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">hasError</span>: <span class="hljs-literal">true</span> };
  }

  componentDidCatch(error, errorInfo) {
    logErrorToService(error, errorInfo);
  }

  render() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state.hasError) {
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Something went wrong.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.props.children;
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ErrorBoundary;
</code></pre>
<p>Wrap your main component with the <code>ErrorBoundary</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/index.js</span>

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

ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ErrorBoundary</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ErrorBoundary</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)
);
</code></pre>
<p><strong>Displaying Errors</strong>: Provide clear and user-friendly error messages to assist users in understanding what went wrong.</p>
<p><strong>Logging Errors</strong>: Implement logging mechanisms to record errors on the server or third-party services for analysis.</p>
<h3 id="heading-103-securing-api-keys">10.3 Securing API Keys</h3>
<p>When working with APIs, especially third-party services, securing API keys is crucial to prevent unauthorized access and potential misuse. Follow these security practices:</p>
<p><strong>Environment Variables</strong>: Store sensitive information, such as API keys, in environment variables rather than hardcoding them in your code.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/services/api.js</span>

<span class="hljs-keyword">const</span> API_KEY = process.env.REACT_APP_API_KEY;

<span class="hljs-comment">// Use API_KEY in your requests</span>
</code></pre>
<p><strong>Restricted Access</strong>: Ensure that your API keys have the minimum required permissions. Avoid granting unnecessary access to your account.</p>
<p><strong>API Key Rotation</strong>: Periodically rotate your API keys to enhance security.</p>
<h3 id="heading-104-monitoring-and-analytics">10.4 Monitoring and Analytics</h3>
<p>Monitoring your application's performance and user interactions helps identify issues and improve the user experience. Consider integrating the following tools:</p>
<p><strong>Google Analytics</strong>: Track user interactions, page views, and user demographics for better insights into user behavior.</p>
<p><strong>Sentry or Bugsnag</strong>: Implement error monitoring tools to receive real-time notifications about issues in your application.</p>
<p><strong>Performance Monitoring</strong>: Use tools like Lighthouse, New Relic, or Datadog to monitor and optimize your application's performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Working with RESTful APIs in React opens up a world of possibilities for building dynamic and data-driven web applications. From fetching and displaying data to handling user input and authentication, this guide has covered a broad range of topics to help you become proficient in integrating APIs with your React projects.</p>
<p>Remember that the key to successful API integration lies in understanding the principles of REST, choosing the right tools and libraries, and following best practices for code organization, error handling, and security. Regular testing, both unit tests and end-to-end tests, ensures the reliability and robustness of your application.</p>
<p>As you continue your journey in React development, stay curious, explore new technologies and trends, and always strive to enhance the performance and user experience of your applications. With the knowledge gained from this guide, you are well-equipped to build powerful and efficient React applications that seamlessly interact with RESTful APIs. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn REST APIs by Building a JavaScript Project ]]>
                </title>
                <description>
                    <![CDATA[ So, you've been learning JavaScript. I bet you're loving it. You've learned the basics and you're starting to get the hang of it. So you might be wondering what to do next. Well, let me introduce you to REST APIs, a powerful tool that you are going t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-rest-apis-javascript-project/</link>
                <guid isPermaLink="false">66d461663bc3ab877dae2251</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Mon, 11 Dec 2023 15:18:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/desktop-preview-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>So, you've been learning JavaScript. I bet you're loving it. You've learned the basics and you're starting to get the hang of it. So you might be wondering what to do next.</p>
<p>Well, let me introduce you to REST APIs, a powerful tool that you are going to add to your arsenal.</p>
<p>In this article, we are going to learn about REST APIs, what they are, and how to use them as a JavaScript developer.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-who-is-this-article-for">Introduction and Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started-with-rest-apis">Getting Started with REST APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-make-requests-with-rest-apis">How to Make Requests with REST APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-http-methods">Understanding HTTP Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-responses-from-the-rest-api">How to Handle Responses from the REST API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-practical-example-how-to-build-a-web-application-with-a-public-rest-api">Practical Example: How to Build a Web Application with a Public Rest API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-who-is-this-article-for">Who is this article for?</h2>
<p>If you're new to the concept of REST APIs, or have heard about them but feel unsure about how they work, this article is tailor-made for you. It's designed for JavaScript developers who are eager to learn the ropes of working with REST APIs.</p>
<h2 id="heading-what-do-i-need-to-continue-with-this-article">What do I need to continue with this article?</h2>
<p>To get the most out of this article, you need some basic knowledge of JavaScript, a browser, and a code editor. Sounds good?</p>
<h2 id="heading-what-will-i-learn-by-the-end-of-this-article">What will I learn by the end of this article?</h2>
<p>By the end of this article, you'll become acquainted with REST APIs. You'll learn how to make your first API request and handle the responses. You'll also build an IP Address Tracker application to put your skills into practice.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/desktop-preview.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Ip Address Tracker Application</em></p>
<h2 id="heading-getting-started-with-rest-apis">Getting Started with REST APIs</h2>
<p>Before we dive into the world of REST APIs, let's take a step back and understand what an API is.</p>
<h3 id="heading-what-is-an-api">What is an API?</h3>
<p>API stands for Application Programming Interface. It acts as a communication channel between two applications, such as a web form submitting data to a database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727423426199/ecb2d72f-b8d0-4821-8040-6cd1b0d507e6.png" alt="ecb2d72f-b8d0-4821-8040-6cd1b0d507e6" class="image--center mx-auto" width="2000" height="770" loading="lazy"></p>
<p><em>Diagram showing how an API helps two applications communicate by requesting and sending data.</em></p>
<p>From the above image, you can see that the API acts as a bridge between the web form and the database. The API handles the <strong>request</strong> made from the web form and sends a <strong>response</strong> back to the web form. In simple terms, that is how APIs work.</p>
<h3 id="heading-what-is-a-rest-api">What is a REST API?</h3>
<p>Now that you know what an API is and how they work, what is REST? REST (Representational State Transfer) is a set of rules (well, you can call them guidelines) that define methods and protocols for how data should be sent, received, and stored.</p>
<p>So basically, REST is a type of API that follows a set of rules that make communication between two applications smooth and organized.</p>
<p>We are not going to go into details about the rules of REST APIs. Here, we just want to know how to use them for now.</p>
<p>There are only two operations that happen when it comes to using APIs: making <strong>a request</strong> and <strong>receiving a response.</strong> We are going to focus on these two operations as we go forward.</p>
<h2 id="heading-how-to-make-requests-with-rest-apis">How to Make Requests with Rest APIs</h2>
<p>REST APIs are typically exposed as an Endpoint, a URL that directs your request. For example, there's a REST API called <code>jsonplaceholder</code> providing random user data. The endpoint to get user data looks like this: https://jsonplaceholder.typicode.com/users.</p>
<p>To get the user data, you make a request to that endpoint using JavaScript's Fetch API:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> request = fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>);
<span class="hljs-built_in">console</span>.log(request.json());
</code></pre>
<p>Run the code above to see it in action. You might wonder why you're getting a Promise instead of the data. That's because the Fetch API returns a Promise, and you need to instruct your code to wait for the API response before finishing.</p>
<p>But how do you do that? You can use <code>async/await</code> method in JavaScript like this:</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Or you can use the <code>.then()</code> method:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</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>Any of the above would do just fine. If you are not familiar with this code, I wrote a <a target="_blank" href="https://www.freecodecamp.org/news/javascript-promises-for-beginners/">beginner's guide to Promises in JavaScript</a> you can check it out.</p>
<p>Hey, now you know how to make a request and <code>GET</code> data from a REST API. But what if you want to add some data to some database using an API? How would you do that?</p>
<p>Well, we still have to use the fetch API, but this time we have to specify the method to be used. We'll take a look at those methods next.</p>
<h2 id="heading-understanding-http-methods">Understanding HTTP Methods</h2>
<p>In addition to the minimal syntax we've seen, the Fetch API takes in some options, and one of those options is the HTTP method.</p>
<p>HTTP methods inform the REST API about the type of request you're making. The common types are POST, GET, PUT, and DELETE, collectively known as CRUD operations (Create, Read, Update, Delete).</p>
<p>Let's look at each HTTP method separately.</p>
<h3 id="heading-get-http-method">GET HTTP Method</h3>
<p>This HTTP method is used to read data from the server when using the REST API. To add a method to the Fetch API, you specify it after the endpoint, like this:</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>When using the Fetch API, it's optional to specify the GET HTTP method. If you don't specify any HTTP method, the Fetch API assumes you're making a GET request. That's why the code you used for your first API request still works fine even without the HTTP method.</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h3 id="heading-post-http-method">POST HTTP Method</h3>
<p>Unlike the <code>GET</code> HTTP method, which retrieves data from an API, the POST HTTP method is used to add data when using REST APIs.</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">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <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(data),
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>If you want to add data to the Rest API using this method, you have to specify the <code>POST</code> HTTP method. You can also see that we passed the data we are trying to add to the <code>body</code> option.</p>
<p>Aside from HTTP methods, the Fetch API also has the <code>body</code> option that we can pass our data when adding data to our API. This data we are trying to add is usually in JSON format, which is why we have to convert our <code>Object</code> to JSON using the <code>JSON.stringify()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };
<span class="hljs-keyword">const</span> json = <span class="hljs-built_in">JSON</span>.stringify(data);
<span class="hljs-built_in">console</span>.log(json);
</code></pre>
<h3 id="heading-put-http-method">PUT HTTP Method</h3>
<p>This method is used to update data when working with REST APIs. You use this method along with the data you want to update, just like the POST HTTP method.</p>
<p>Let's update the user with the <code>id</code> 11 we created above.</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">UpdateData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users/2'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <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(data),
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">age</span>: <span class="hljs-number">42</span> }; <span class="hljs-comment">// update the age</span>

UpdateData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h3 id="heading-delete-http-method">DELETE HTTP Method</h3>
<p>This method, as the name implies, is used to delete data permanently from a server when using REST APIs. You don't pass any data to the body when using this method. Let's delete the user we created above:</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">UpdateData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users/2'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span> });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

UpdateData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Having learned all this, you can now confidently create, read, update, and delete data from the server by using REST APIs.</p>
<p>Now, when making requests to a REST API, the HTTP method and the body options are not the only things you can specify along with your request. You can also pass along <code>headers</code> with your request.</p>
<p>Headers allow you to provide additional information about the request you are making. For example, we can tell the REST API the type of content we are sending beforehand.</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">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <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(data),
    <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>The<code>headers: { "Content-Type": "application/json"}</code> header simply tells the REST API beforehand that we are trying to add data that is in JSON format. Of course, this is completely optional.</p>
<p>Up until now, we have only looked at making requests. lets now look at handling requests from a REST API</p>
<h2 id="heading-how-to-handle-responses-from-the-rest-api">How to Handle Responses from the Rest API</h2>
<p>Any time you make a request to an API, you will always get a response. There are a couple types of responses you can get back from a Rest API call. You either get a 2XX success response or a 4XX/5XX error response. In your JavaScript code, you'll need to handle these responses accordingly.</p>
<p>Don't worry – we're going to break down what the above responses mean.</p>
<h3 id="heading-understanding-response-codes">Understanding Response codes</h3>
<p>As stated above, anytime you make a request, you will always get a response. Depending on the status of your response code, you can determine if a response was successful or not.</p>
<h4 id="heading-2xx-success-status-code">2XX Success Status Code</h4>
<p>Success responses are usually in the range of 200 to 299 HTTP status codes. The most common success code is 200 OK, indicating that the request was successful. When you receive a successful response, you can handle the data returned by the API.</p>
<p>Here's an example of that shows the status code of our response:</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-built_in">console</span>.log(response.status);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>If you get a <code>200</code> status code, it means that the request was successful and OK.</p>
<p>We should always use this status code to check if our request was successful before we try to use the data returned from an API request.</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (request.status == <span class="hljs-number">200</span>) {
    <span class="hljs-comment">// Request was successful</span>
    <span class="hljs-built_in">console</span>.log(request.status);
  }
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Additionally, you can also use the<code>Response.ok</code> property to check if the request was successful; this property will return <code>true</code> if the request was successful.</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (response.ok) {
    <span class="hljs-comment">// Request was successful</span>
    <span class="hljs-built_in">console</span>.log(response.status);
  }
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h4 id="heading-4xx5xx-error-status-code">4XX/5XX Error Status Code</h4>
<p>When you make a request to an API, and you don't receive a success status code, you will either get a 400-499 or 500-599 error code. The error code you will receive will fall into one of these ranges.</p>
<p>Both of these status codes usually indicate an error. The 400–499 error codes indicate that there's something wrong with your request, while the 500–599 error codes indicate that error is coming from the server.</p>
<p>Consider the example below where we intentionally made a request to a non-existent endpoint (<a target="_blank" href="https://jsonplaceholder.typicode.com/nonexistent"><code>https://jsonplaceholder.typicode.com/nonexistent</code></a>) to trigger a <code>404 Not Found</code> error.</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">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/nonexistent'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">body</span>: data, <span class="hljs-comment">// don't convert the data to json</span>
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (response.ok) {
    <span class="hljs-built_in">console</span>.log(response);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`An error with status code <span class="hljs-subst">${response.status}</span> occured`</span>);
  }
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>The status code <code>404</code> we received here indicates that there's something wrong with our request.</p>
<p>I did not cover all the status codes here, but if you are looking for a comprehensive list of the status codes, you can take a look at this <a target="_blank" href="https://www.restapitutorial.com/httpstatuscodes.html">guide</a>.</p>
<p>Now depending on the response you receive, you can show different things to your users.</p>
<ul>
<li><p>if you receive a success status code, you can use the data to build your application as you deem fit</p>
</li>
<li><p>If you receive an error status code, you can show an Error message to your users as well</p>
</li>
</ul>
<h3 id="heading-how-to-handle-the-response-body">How to handle the response body</h3>
<p>Depending on the type of request you make, you are going to get back data as a response. To get this data we use the <code>request.json();</code>. We have used this a couple of times already – it will get the request body and parse the data back to an object that we can use.</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json(); <span class="hljs-comment">// parse the data</span>

  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>You don't need to do anything else in order to process the data returned from your API request.</p>
<p>Aside from the request body, you also get the <code>headers</code> along with the response. This can be useful if, for example, you want to check the type of data returned by your API request beforehand:</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">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);

  <span class="hljs-keyword">const</span> dataType = request.headers.get(<span class="hljs-string">'content-type'</span>);

  <span class="hljs-keyword">if</span> (dataType.includes(<span class="hljs-string">'application/json'</span>)) {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json(); <span class="hljs-comment">// parse the data</span>
    <span class="hljs-built_in">console</span>.log(response);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'We expected the data to be in json format'</span>);
  }
}
GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Well, enough of all the talk. Let's roll up our sleeves and try a practical example.</p>
<h2 id="heading-practical-example-how-to-build-a-web-application-with-a-public-rest-api">Practical Example: How to Build a Web Application with a Public Rest API</h2>
<p>I feel like we have learned a lot already, so let's put our new Rest API skills into practice, shall we?</p>
<p>Our task is to build a web application with an IP address API. It'll retrieve information about an IP address and display the location of the IP address on a map with some other information. This is what it is supposed to look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727424349562/2f32e4cf-908f-411b-8eea-89e97984b18a.jpeg" alt="2f32e4cf-908f-411b-8eea-89e97984b18a" class="image--center mx-auto" width="1440" height="800" loading="lazy"></p>
<p><em>Application we'll build</em></p>
<p>To build this we are going to use:</p>
<ul>
<li><p><a target="_blank" href="https://geo.ipify.org/">IP Geolocation API by IPify</a> to get the IP address locations.</p>
</li>
<li><p>The endpoint for the API: <a target="_blank" href="https://geo.ipify.org/api/v2/country,city?apiKey=XXXXXXXX&amp;ipAddress=XXXXXXX"><code>https://geo.ipify.org/api/v2/country,city?apiKey=XXXXXXXX&amp;ipAddress=XXXXXXX</code></a></p>
</li>
<li><p>To get the API key you have to sign up for an account with <a target="_blank" href="https://geo.ipify.org/">IPify</a></p>
</li>
<li><p>To generate the map, we are going to be using <a target="_blank" href="https://leafletjs.com/">LeafletJS</a></p>
</li>
</ul>
<p>Now that we have that out of the way, let's build the HTML and CSS of the web application. If you are confident about your HTML and CSS skills, try building the web page on your own. Here's my implementation:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/GRzzeNp" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Now that we have the HTML and CSS out of the way, the first thing we need to do is to get the IP address the user entered. So create a <code>index.js</code> file and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Select form */</span>
<span class="hljs-keyword">const</span> search_form = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.header_form'</span>);

search_form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">/* stop form from auto submiting on click */</span>
  event.preventDefault();

  <span class="hljs-comment">/* get the value of the form field */</span>
  <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#search'</span>).value;

  <span class="hljs-built_in">console</span>.log(value);
});
</code></pre>
<p>Submit the the form to see the value that you entered in the HTML input form.</p>
<p>Next we need to pass that value into a function <code>search_Ip_Address()</code>. It actually makes a GET request to fetch our location data and uses the data to update the UI of our web application:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Select form */</span>
<span class="hljs-keyword">const</span> search_form = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.header_form'</span>);

search_form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">/* stop form from auto submiting on click */</span>
  event.preventDefault();

  <span class="hljs-comment">/* get the value of the form field */</span>
  <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#search'</span>).value;

  <span class="hljs-comment">/* Pass the Ip address to the search_Ip_Address() function */</span>
  search_Ip_Address(value);
});

<span class="hljs-comment">/* Search for an IpAddress */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search_Ip_Address</span>(<span class="hljs-params">ip_address</span>) </span>{
  <span class="hljs-keyword">const</span> api_key = <span class="hljs-string">'xxxxxxxxxxxxxxxxxxxxxxx'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://geo.ipify.org/api/v2/country,city?apiKey=<span class="hljs-subst">${api_key}</span>&amp;ipAddress=<span class="hljs-subst">${ip_address}</span>`</span>,
  );
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-comment">/* Update the UI on the page */</span>
  <span class="hljs-keyword">const</span> { location, ip, isp } = response;
  update_ui(ip, location.city, location.timezone, isp);
}

<span class="hljs-comment">/* update UI function */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update_ui</span>(<span class="hljs-params">ip_address, location, timezone, isp</span>) </span>{
  <span class="hljs-comment">/* select all the elements on the page */</span>
  <span class="hljs-keyword">const</span> address = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.address'</span>);
  <span class="hljs-keyword">const</span> city = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.location'</span>);
  <span class="hljs-keyword">const</span> utc = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.utc'</span>);
  <span class="hljs-keyword">const</span> isprovider = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.isp'</span>);

  <span class="hljs-comment">/* Update all the elements on the page */</span>
  address.textContent = ip_address;
  city.textContent = location;
  utc.textContent = <span class="hljs-string">'UTC'</span> + timezone;
  isprovider.textContent = isp;
}
</code></pre>
<p>Next we need to create our map. To begin, add the following to the <code>head</code> section of your HTML file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  ...
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
    <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"</span>
    <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="</span>
    <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">""</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://unpkg.com/leaflet@1.9.4/dist/leaflet.js"</span>
    <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="</span>
    <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">""</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  ...
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>Also make sure you have a div element on the page with an <code>id</code> of map:</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">"map"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"map"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Next we need to create a function that will create the map for us. So in your <code>script.js</code> add the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* create the map */</span>
<span class="hljs-keyword">let</span> map;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create_map</span>(<span class="hljs-params">lat, lng</span>) </span>{
  map = L.map(<span class="hljs-string">'map'</span>).setView([lat, lng, country, region], <span class="hljs-number">14</span>);
  L.tileLayer(<span class="hljs-string">'https://tile.openstreetmap.org/{z}/{x}/{y}.png'</span>, {
    <span class="hljs-attr">maxZoom</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">attribution</span>:
      <span class="hljs-string">'&amp;copy; &lt;a href="http://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt;'</span>,
  }).addTo(map);

  L.marker([lat, lng])
    .addTo(map)
    .bindPopup(<span class="hljs-string">`<span class="hljs-subst">${region}</span>, <span class="hljs-subst">${country}</span>`</span>)
    .openPopup();
}
</code></pre>
<p>Lastly we just need to call the <code>create_map()</code> function any time the user searches for an IP address.</p>
<p>To call the <code>create_map()</code> when the user searches for an Ip address, update the <code>search_Ip_Address()</code> function:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Search for an IpAddress */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search_Ip_Address</span>(<span class="hljs-params">ip_address</span>) </span>{
  <span class="hljs-keyword">const</span> api_key = <span class="hljs-string">'at_HhKzCe09UZIYJC9pY7YTg7kMMUzZd'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://geo.ipify.org/api/v2/country,city?apiKey=<span class="hljs-subst">${api_key}</span>&amp;ipAddress=<span class="hljs-subst">${ip_address}</span>`</span>,
  );
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">const</span> { location, ip, isp } = response;

  <span class="hljs-comment">/* Update the ui on the page */</span>
  update_ui(ip, location.city, location.timezone, isp);

  <span class="hljs-comment">/* Update the map on the page */</span>
  <span class="hljs-comment">/* first remove all map instances if any */</span>
  <span class="hljs-keyword">if</span> (map !== <span class="hljs-literal">undefined</span> &amp;&amp; map !== <span class="hljs-literal">null</span>) {
    map.remove();
  }
  create_map(location.lat, location.lng, location.country, location.region);
}
</code></pre>
<p>Lastly, just call the <code>search_Ip_Address()</code> function when the page finishes loading:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> defaultIp = <span class="hljs-string">'197.210.78.172'</span>;
search_Ip_Address(defaultIp);
</code></pre>
<p>And there you go – a nice IP tracker web application. I hope that building this application helped you reinforce your newfound REST API skills.</p>
<p>To provide you with an opportunity for practice, here's a challenge you can undertake. Below is the final preview of the web app:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/rNPPoag" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-challenge">Challenge:</h3>
<p>Currently, our IP tracker application lacks error handling. For instance, if a user enters a random word in the search input field that is not a valid IP address, the entire application will break.</p>
<p>As conscientious developers, we should always be vigilant about errors and handle them gracefully. Therefore, your challenge is twofold:</p>
<ol>
<li><p>Implement input validation to ensure that the entered value is always a valid IP address. If the user enters an invalid IP address, display an error message.</p>
</li>
<li><p>Handle all unforeseen errors that users may encounter during the application's usage.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Knowing how to work with REST APIs is a key skill that developers must have. In this article, you learned about REST APIs and how to use them to develop your own applications.</p>
<p>If you have any questions, feel free to message me on Twitter at <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a>, and don't forget to follow me for more insights and updates. Happy coding!</p>
<p>The example used in this tutorial was gotten from <a target="_blank" href="http://frontendmentor.io">frontendmentor.io</a> <a target="_blank" href="https://www.frontendmentor.io/challenges/ip-address-tracker-I8-0yYAH0">IP address tracker challenge on Frontend Mentor</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ API Integration Patterns – The Difference between REST, RPC, GraphQL, Polling, WebSockets and WebHooks ]]>
                </title>
                <description>
                    <![CDATA[ API stands for Application Programming Interface. The “I” in API is the key part that explains its purpose. The interface is what the software presents to other humans or programs, allowing them to interact with it. A good analogy for an interface is... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/api-integration-patterns/</link>
                <guid isPermaLink="false">66d45e037df3a1f32ee7f7f9</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ webhooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ websocket ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Adetunji ]]>
                </dc:creator>
                <pubDate>Mon, 09 Oct 2023 15:14:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/FCC-cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>API stands for Application Programming Interface. The “I” in API is the key part that explains its purpose.</p>
<p>The <em>interface</em> is what the software presents to other humans or programs, allowing them to interact with it.</p>
<p>A good analogy for an interface is a remote control. Imagine you have a universal remote that can control your TV, lights, and fan.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28286169-80d5-49f6-b302-65c8cb10fdcb_1762x1070.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Image showing a remote control and a TV, light fixture, and fan.</em></p>
<p>Let’s break down what a universal remote control can do:</p>
<ol>
<li><p>The remote control has various buttons, each serving a different purpose. One button might change the channel, while another can dim the lights of the chandelier, and another can turn on the fan.</p>
</li>
<li><p>When you press a button, it sends a specific signal via infrared, bluetooth, or wifi to the object you are controlling, instructing it to perform a particular action.</p>
</li>
<li><p>The key thing about the remote is that it allows you to interact with the TV, chandelier, and the fan without understanding the internal workings of these objects. All that complexity is abstracted away from you. You simply press a button, and you get a response that you can observe straight away.</p>
</li>
</ol>
<p>APIs work in a similar way.</p>
<ol>
<li><p>APIs can have various endpoints, each designed to perform a specific action. One endpoint might retrieve data, while another updates or deletes it.</p>
</li>
<li><p>When you send a request to an endpoint, it communicates with the server using HTTP methods – GET, POST, PUT, DELETE to instruct it to perform a particular action (like retrieving, sending, updating, or deleting data).</p>
</li>
<li><p>The key thing about APIs, as with remote controls, is that APIs abstract away the inner workings of the server and the database behind the API. The API allows users, developers and applications to interact with a software application or platform without needing to understand its internal code or database structure. You simply send a request, the server processes it and provides a response.</p>
</li>
</ol>
<p>This analogy only holds true for so long, as APIs are more complex than a remote control. But the basic principles of operation between an API and a universal remote are quite similar.</p>
<p>This article will explain API integration patterns, which can be split into two broad groups: Request-response (REST, RPC &amp; GraphQL) and event driven APIs (Polling, WebSockets &amp; WebHooks).</p>
<h2 id="heading-request-response-integration">Request-Response Integration</h2>
<p>In a request-response integration, the client initiates the action by sending a request to the server and then waits for a response.</p>
<p>Different patterns of the request-response integration exist, but at a high level, they all conform to the same rule of the client initiating a request and waiting for a response from the server.</p>
<h3 id="heading-1-rest">1. REST</h3>
<p>Rest stands for Representational State Transfer – the acronym is a combination of the first one or two letters from these three words. This is the simplest and most popular form of a request-response integration.</p>
<p>REST APIs use a <a target="_blank" href="https://lightcloud.substack.com/i/104443280/stateless-architecture">stateless</a>, client-server communication model, wherein each message contains all the information necessary to understand and process the message.</p>
<p>REST is all about resources. Resources are entities that the API exposes, which can be accessed and manipulated using URL paths.</p>
<p>To understand REST APIs, consider the following analogy. Imagine you go into a restaurant to order some food. The menu is extensive and items are categorically organised. Each item on the menu can be equated to a resource.</p>
<p>First, you call the waiter to get their attention, then you place an order. Each request receives a response, before you proceed with another request, like ordering a dish.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F267e1809-4111-43dc-8c6d-aa7bdf764c54_1102x1022.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for REST API</em></p>
<p>In REST API terms, the client initiates requests to the server by specifying exactly what it wants using HTTP methods (such as GET, POST, PUT, DELETE) on specific URLs (the menu items). Each interaction is stateless, meaning that each request from the client to the server must contain all the information needed to understand and process the request.</p>
<p>The server then processes the request and returns the appropriate response – in our analogy, bringing the ordered item to the table.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd86ab699-f5a2-4c93-9ac8-ee0af83df14d_1174x916.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Simple sequence diagram for REST API</em></p>
<h3 id="heading-2-rpc">2. RPC</h3>
<p>RPC stands for Remote Procedure Call. Unlike REST APIs which are all about resources, RPC is all about actions. With RPC, the client executes a block of code on the server</p>
<p>Think of a restaurant without a menu. There is no dish you can request in this restaurant. Instead, you request a specific action to be performed by the restaurant.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d9a0ce7-d263-4932-b159-a3234677cf71_1518x926.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for RPC</em></p>
<p>With a REST API, the guest would have simply asked for some fish and chips. With RPC, they have to give instructions on what they want the kitchen to prepare.</p>
<p>In the RPC pattern, the client calls a specific procedure on the server and waits for the result. The procedure to prepare and what gets prepared are tightly bound together. This might give the client very specific and tailored results, but lacks the flexibility and ease of use of REST.</p>
<p>There is a reason most restaurants use menus, instead of following the custom requests of their customers. This partly explains why RPC is a less popular integration pattern compared to REST.</p>
<h3 id="heading-3-graphql">3. GraphQL</h3>
<p>With GraphQL, the client specifies exactly what data it needs, which can include specific fields from various resources. The server processes this query, retrieves the exact data, and returns it to the client.</p>
<p>This enables the client to have a high degree of flexibility and only retrieve exactly the data it needs. It also requires the server to be capable of handling more complex and unique queries.</p>
<p>In this way, GraphQL is a more customisable form of REST. You still deal with resources (unlike actions in RPC) but you can customise how you want the resource returned to you.</p>
<p>Think of a restaurant that allows you to customise your own dish by specifying exact quantities or ingredients you want.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9327807-033d-4e21-b649-0de8e33272bd_1518x858.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for GraphQL</em></p>
<p>This may look similar to the RPC pattern, but notice that the customer is not saying how the food should be made, they're just customising their order by removing some ingredients (no salt) and reducing the number of some items (two pieces of fish instead of four).</p>
<p>One of the drawbacks of GraphQL is that it adds complexity to the API since the server needs to do additional processing to parse complex queries. This additional complexity would also apply to the restaurant analogy, since each order would need to be customised to the guest.</p>
<p>GraphQL has one clear benefit over REST and RPC. Since clients can specify exactly what they need, the response payload sizes are typically smaller, which means faster response times.</p>
<h2 id="heading-event-driven-integration">Event Driven Integration</h2>
<p>This integration pattern is ideal for services with fast changing data.</p>
<p>Some of these integration patterns are also <a target="_blank" href="https://lightcloud.substack.com/p/synchronous-and-asynchronous-communication">asynchronous</a> and initiated by the server, unlike the request-response patterns which are <a target="_blank" href="https://lightcloud.substack.com/p/synchronous-and-asynchronous-communication">synchronous</a> and initiated by the client.</p>
<h3 id="heading-1-polling">1. Polling</h3>
<p>Let’s bring back the restaurant analogy. When you order food, it will take some time for it to be prepared.</p>
<p>You can get updates on your order by asking the waiter if it is ready yet. The more frequently you ask, the closer you will be to having real-time information about your order.</p>
<p>This, however, puts unnecessary strain on the waiter since they have to constantly check the status of your order and have them update you whenever you ask.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F661f8761-5b3e-426f-aa55-fbadc25bd226_892x888.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for polling</em></p>
<p>Polling is when the client continuously asks the server if there is new data available, with a set frequency. It's not efficient because many requests may return no new data, thus unnecessarily consuming resources.</p>
<p>The more frequently you poll (make requests) the closer the client gets to real-time communication with the server.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a8467fc-580f-46e4-b134-7dc3128f044a_1174x954.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Simple sequence diagram showing polling in action</em></p>
<p>Most of the requests during polling are wasted, since they only return something useful to the client once there is a change on the server.</p>
<p>There is, however, another version of polling called long polling. With long polling, the waiter does not respond to the guest straightaway about the status of the order. Instead, the waiter only responds if there is an update.</p>
<p>Naturally, this only works if the guest and the waiter agree beforehand that a slow response from the waiter does not mean that the waiter is being rude and the guest is being ignored.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff76ea285-2629-4aea-8b89-81d500484835_892x888.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for long polling</em></p>
<p>With long polling, the server does not respond to the client immediately. It waits until something has changed before responding.</p>
<p>As long as the client and server agree that the server will hold on to the client’s request, and the connection between the client and server remains open, this pattern works and can be more efficient than simply polling.</p>
<p>These two assumptions for long polling may be unrealistic, though – the server can lose the client's request and/or the connection can be broken.</p>
<p>To address these limitations, long polling adds extra complexity to the process by requiring a directory of which server contains the connection to the client, which is used to send data to the client whenever the server is ready.</p>
<p>Standard polling on the other hand can remain <a target="_blank" href="https://lightcloud.substack.com/i/104443280/stateless-architecture">stateless</a>, making it more <a target="_blank" href="https://lightcloud.substack.com/i/59017006/fault-tolerance">fault tolerant</a> and scalable.</p>
<h3 id="heading-2-websockets">2. WebSockets</h3>
<p>WebSockets provide a persistent, two-way communication channel between the client and server. Once a WebSocket connection is established, both parties can communicate freely, which enables real-time data flows and is more resource-efficient than polling.</p>
<p>Using the restaurant analogy again, a guest orders a meal and then establishes a dedicated communication channel with the waiter so they can freely communicate back and forth about updates or changes to the order until the meal is ready. This means the waiter can also initiate the communication with the guest, which is not the case for the other integration patterns mentioned so far.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffebdcac2-f175-4ea1-bd19-1234702def98_892x888.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Restaurant analogy for WebSockets</em></p>
<p>WebSockets are similar to long polling. They both avoid the wasteful requests of polling, but WebSockets have the added benefit of having a persistent connection between the client and the server.</p>
<p>WebSockets are ideal for fast, live streaming data, like real-time chat applications. The downside of WebSockets is that the persistent connection consumes bandwidth, so may not be ideal for mobile applications or in areas with poor connectivity</p>
<h3 id="heading-3-webhooks">3. WebHooks</h3>
<p>WebHooks allow the server to notify the client when there's new data available. The client registers a callback URL with the server and the server sends a message to that URL when there is data to send.</p>
<p>With WebHooks, the client sends requests as usual, but can also listen for and receive requests like a server.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d687228-bff2-45d4-a7ac-8ebe2bb07094_1458x954.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Simple sequence diagram showing WebHooks in action</em></p>
<p>Using the restaurant analogy, when the guest orders a meal, they give the waiter a bell (analogous to the callback URL). The waiter goes to the kitchen and rings the bell as soon as the meal is ready. This allows the client to know, in real-time, about the progress of his order.</p>
<p>WebHooks are superior to polling because you get real-time updates from the server once something changes, without having to make frequent, wasteful requests to the server about that change.</p>
<p>They're also superior to long polling because long polling can consume more client and server resources as it involves keeping connections open, potentially resulting in many open connections.</p>
<h2 id="heading-bringing-it-together">Bringing it Together</h2>
<p>In conclusion, APIs are crucial tools in software development, allowing users and applications to interact with software without understanding its inner workings.</p>
<p>They come in different integration patterns, such as REST, RPC, GraphQL, Polling, WebSockets, and WebHooks.</p>
<p>If you need a simple request-response integration, then REST, RPC or GraphQL could be ideal. For real-time or near-real-time applications, polling, WebScokets, or WebHooks are ideal.</p>
<p>As with any design problem, the right choice depends on the business case and what tradeoffs you are willing to tolerate.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Avoid the N+1 Query Problem in GraphQL and REST APIs [with Benchmarks] ]]>
                </title>
                <description>
                    <![CDATA[ By Mohamed Mayallo The N+1 query problem is a performance issue you might face while building APIs, regardless of whether they're GraphQL or REST APIs. In fact, this problem occurs when your application needs to return a set of data that includes rel... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/n-plus-one-query-problem/</link>
                <guid isPermaLink="false">66d46013a326133d12440a21</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 07 Jul 2023 17:59:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/N-1-Query-Problem.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mohamed Mayallo</p>
<p>The N+1 query problem is a performance issue you might face while building APIs, regardless of whether they're GraphQL or REST APIs.</p>
<p>In fact, this problem occurs when your application needs to return a set of data that includes related nested data – for example, a post that includes comments.</p>
<p>But how can you fix this problem? To avoid this issue, you should understand what is it and how it occurs.</p>
<p>So in this tutorial, you'll learn what the N+1 query problem is, why it is easy to fall into it, and how you can avoid it.</p>
<p>Before starting, it is good to know:</p>
<ul>
<li>The examples in this article are just for the sake of simplicity.</li>
<li><code>SELECT *</code> is very bad, and you should avoid it.</li>
<li>You should care about pagination if you’re working with large data sets.</li>
</ul>
<p>You can find the examples in this article in this <a target="_blank" href="https://github.com/Mohamed-Mayallo/n_plus_one_problem_benchmarks">repo</a>. Let's dive in.</p>
<h2 id="heading-understanding-the-n1-query-problem">Understanding the N+1 Query Problem</h2>
<p>The N+1 problem occurs when your application needs to return a set of data that includes related data that exists in:</p>
<ul>
<li>Another table.</li>
<li>Another database (in the case of microservices, for example)</li>
<li>Or even another third-party service.</li>
</ul>
<p>In other words, you need to execute extra database queries or external requests to return the nested data.</p>
<p>If you are wondering about what the name means (N+1), follow the below example, which uses a single database:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/related-data.drawio.png" alt="Post and Comment tables | By Author" width="600" height="400" loading="lazy">
<em>Illustration of N+1 problem</em></p>
<p>As you can see, the relationship between <code>Post</code> and <code>Comment</code> is one-to-many, respectively.</p>
<p>So, if your application needs to return a list of posts and their related comments, you might end up with this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>); <span class="hljs-comment">// Get all posts (1 database query)</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) {
    <span class="hljs-comment">// For sure, you can replace the following query with an external request if you need to retrieve the post's comments from another service</span>
    <span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" = <span class="hljs-subst">${post.id}</span>`</span>); <span class="hljs-comment">// Get all comments for every post (n database query for n posts)</span>
    post.comments = comments;
}
</code></pre>
<p>So, you have executed <strong>N</strong> queries to retrieve every post’s comments and <strong>1</strong> query to retrieve all posts <strong>(N comments queries + 1 posts query).</strong></p>
<p>But, why you should be aware of this problem?</p>
<h2 id="heading-why-is-the-n1-query-problem-a-serious-issue">Why Is the N+1 Query Problem a Serious Issue?</h2>
<p>Here are some reasons why the N+1 query problem can cause serious performance issues in your application:</p>
<ol>
<li>Your application makes a lot of database queries or external requests to retrieve a list of data like posts.</li>
<li>The more data your application retrieves, the slower your request is going to be and the more resources your application is going to consume.</li>
<li>A large data set might end up with notable network latency.</li>
<li>It is going to be challenging to scale the application to handle larger data sets.</li>
</ol>
<p>On top of that, you are going to see the performance impact in numbers in the benchmarks section later in this article.</p>
<p>Now that you understand the N+1 query problem and its impact on your application, let’s introduce some effective ways you can avoid this problem.</p>
<h2 id="heading-strategies-to-avoid-the-n1-query-problem">Strategies to Avoid the N+1 Query Problem</h2>
<p>Fortunately, there are a few simple strategies you can follow to avoid the N+1 query problem.</p>
<p>Let’s apply them to our previous example.</p>
<h3 id="heading-1-eager-loading-using-sql-joins-for-example">1) Eager Loading (Using SQL Joins, for example)</h3>
<p>In this strategy, instead of returning the post’s comments separately for every post, you can use <strong>SQL Joins</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> postsAndComments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`
    SELECT * 
    FROM "Post"
    JOIN "Comment"
    ON "Comment"."post_id" = "Post"."post_id"
`</span>);
</code></pre>
<p>When you're using this strategy, it's good to know that:</p>
<ul>
<li>It is only one database query to return all posts and their nested comments.</li>
<li>You can't apply this strategy if you are consuming your data sets from a different database or service.</li>
</ul>
<h3 id="heading-2-batch-loading">2) Batch Loading</h3>
<p>In this strategy, your code should follow the below steps:</p>
<ul>
<li>Execute one request to retrieve all posts.</li>
<li>Execute another request to load a batch of posts’ comments instead of loading every post’s comments separately.</li>
<li>Map every comment to its corresponding parent post.</li>
</ul>
<p>Let’s jump into an example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>), <span class="hljs-comment">// 1- Retrieve all posts in one request</span>
    postsIds = posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> post.id),
    postsComments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" IN (<span class="hljs-subst">${postsIds}</span>)`</span>); <span class="hljs-comment">// 2- retrieve all posts’ comments in another request</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) { <span class="hljs-comment">// 3- Map every comment to its parent post</span>
    <span class="hljs-keyword">const</span> comments = postsComments.filter(<span class="hljs-function"><span class="hljs-params">comment</span> =&gt;</span> comment.post_id === post.id);
    post.comments = comments;
}
</code></pre>
<p>As you see, in this strategy, there are just two requests: one to retrieve all posts and another one to retrieve their comments.</p>
<h3 id="heading-3-caching">3) Caching</h3>
<p>You may be familiar with caching and its impact on any application's performance.</p>
<p>You can implement caching on your client side or server side using <a target="_blank" href="https://redis.io/">Redis</a>, <a target="_blank" href="https://memcached.org/">Memcached</a>, or any other similar tool. Wherever you can properly use caching, it significantly pushes your application's performance.</p>
<p>Let’s get back to our example and cache the posts’ comments in a Redis store.</p>
<pre><code class="lang-js">    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>),
        postsIds = posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> post.id),
        cachedPostsComments = getPostsCommentsFromRedis(postsIds);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) {
    <span class="hljs-keyword">const</span> comments = cachedPostsComments.filter(<span class="hljs-function"><span class="hljs-params">comment</span> =&gt;</span> comment.post_id === post.id);
    post.comments = comments;
}
</code></pre>
<p>As you might guess, you can cache the posts’ comments or even the posts themselves which significantly minimizes the load on databases.</p>
<h3 id="heading-4-lazy-loading">4) Lazy Loading</h3>
<p>In this strategy, you are distributing the responsibility between the server side and the client side.</p>
<p>You shouldn’t return all data at once from the server side. Instead, you prepare two endpoints for the client side like this:</p>
<ul>
<li><code>GET /api/posts</code>: Retrieves all posts.</li>
<li><code>GET /api/comments/:postId</code>: Retrieves a post’s comments on demand.</li>
</ul>
<p>And now, the data retrieval is up to the client side.</p>
<p>This strategy is very useful because:</p>
<ul>
<li>It enables the client side to load the parent post first and display its content, and then load its related comments lazily. So users don't have to wait for the entire data set to be returned from the server side.</li>
<li>You have full control over sorting, filtering, pagination and so on over every endpoint.</li>
</ul>
<p>The key point of this strategy is that it gets rid of nested data like comments and flattens all data sets in their own endpoint.</p>
<h3 id="heading-5-graphql-dataloader">5) GraphQL Dataloader</h3>
<p>As you might guess, this strategy works with GraphQL APIs.</p>
<p>Dataloader is a GraphQL utility that works by batching multiple database queries into one request. So, it uses the Batch Loading strategy under the hood.</p>
<p>Let’s jump into our example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> DataLoader = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dataloader'</span>);

<span class="hljs-comment">// 1- GraphQL Schema Definition</span>
<span class="hljs-keyword">const</span> typeDefs = gql<span class="hljs-string">`
  type Post {
    post_id: ID!
        comments: [Comment]
  }

    type Comment {
        comment_id: ID!
    post_id: ID!
  }

  type Query {
    posts: [Post]
  }
`</span>;

<span class="hljs-comment">// 2- Resolve the GraphQL Schema</span>
<span class="hljs-keyword">const</span> resolvers = {
  <span class="hljs-attr">Query</span>: {
    <span class="hljs-attr">posts</span>: <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>);
            <span class="hljs-keyword">return</span> posts;
    }
  },

  <span class="hljs-attr">Post</span>: {
    <span class="hljs-attr">comments</span>: <span class="hljs-function">(<span class="hljs-params">post, args, { dataLoaders }</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> dataLoaders.commentsLoader.load(post.id);
    }
  }
};

<span class="hljs-comment">// 3- Define Dataloaders</span>
<span class="hljs-keyword">const</span> commentsBatchFunction = <span class="hljs-keyword">async</span> postsIds =&gt; {
      <span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" IN (<span class="hljs-subst">${postsIds}</span>)`</span>);
        <span class="hljs-keyword">const</span> groupedComments = comments.reduce(<span class="hljs-function">(<span class="hljs-params">tot, cur</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (!tot[cur.post_id]) {
        tot[cur.post_id] = [cur];
      } <span class="hljs-keyword">else</span> {
        tot[cur.post_id].push(cur);
      }
      <span class="hljs-keyword">return</span> tot;
    }, {});
        <span class="hljs-keyword">return</span> postsIds.map(<span class="hljs-function">(<span class="hljs-params">postId</span>) =&gt;</span> groupedComments[postId]);
    },
    createCommentsLoader = <span class="hljs-keyword">new</span> DataLoader(commentsBatchFunction),
    createDataloaders = <span class="hljs-function">() =&gt;</span> ({
        <span class="hljs-attr">commentsLoader</span>: createCommentsLoader()
    });

<span class="hljs-comment">// 4- Inject Dataloaders in the GraphQL Context</span>
<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({
    typeDefs,
    resolvers,
    <span class="hljs-attr">context</span>: <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">dataLoaders</span>: createDataloaders(),
    }
  }
});
</code></pre>
<p>So how does it work? To get more detailed information, you can check out the <a target="_blank" href="https://github.com/graphql/dataloader">documentation</a>. But we'll go through the basics here.</p>
<p>The key point of the Dataloader is the <a target="_blank" href="https://github.com/graphql/dataloader#batch-function">Batch Function</a>. Here, the batch function <code>commentsBatchFunction</code> takes an array of keys <code>postsIds</code> and returns a <a target="_blank" href="https://mayallo.com/asynchronous-javascript/">Promise which resolves</a> to an array of values <code>comments</code>, <code>[ [post1comment1, post1comment2], [post2comment1], ... ]</code>.</p>
<p>On top of that, the batch function has two constraints:</p>
<ul>
<li>The size of the keys array <code>postsIds</code> must equal the values array <code>comments</code>. In other words, this expression must be true: <code>postsIds.length === comments.length</code>.</li>
<li>Each index in the keys array <code>postsIds</code> must correspond to the values array <code>comments</code>. So you might note that I looped over the <code>postsIds</code> to map each corresponding comment.</li>
</ul>
<p>As a result, you can see that GraphQL Dataloader uses the second strategy (Batch Loading) under the hood.</p>
<p>Let’s get back to our example to walk through its implementation:</p>
<ol>
<li>First, we defined the GraphQL schema.</li>
<li>Then we resolved the GraphQL schema. Keep in mind, if you resolved the comments in the <code>Post</code> type using this query <code>await rawSql('SELECT * FROM "Comment" WHERE "post_id" = ' + post.id);</code>, you’re going to fall into the N+1 query problem.</li>
<li>Next, we defined the comments batch function and then created the comments dataloader.</li>
<li>Finally, we injected dataloaders in the <a target="_blank" href="https://www.apollographql.com/docs/apollo-server/data/context/">GraphQL Context</a> to be able to use them in resolvers.</li>
</ol>
<p>So, by using GraphQL Dataloader, if you have 10 posts and every post has 5 comments, you would end up with two queries – one to retrieve the 10 posts and another one to retrieve their comments.</p>
<p>Take a look at the following screenshot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Code_1K9XMH0CHB.png" alt="Database queries with GraphQL Dataloader and without it" width="600" height="400" loading="lazy">
<em>Illustration of process with and without Dataloader</em></p>
<h2 id="heading-benchmarks-about-n1-query-problem">Benchmarks About N+1 Query Problem</h2>
<p>In this section, let’s compare each strategy in terms of performance.</p>
<table>
<thead>
<tr>
<th>N+1 in REST API</th>
<th>Eager Loading Strategy</th>
<th>Batch Loading Strategy</th>
<th>Caching Strategy</th>
<th>N+1 in GraphQL API</th>
<th>GraphQL Dataloader</th>
</tr>
</thead>
<tbody>
<tr>
<td>2.139</td>
<td>0.065</td>
<td>0.048</td>
<td>0.019</td>
<td>2.44</td>
<td>0.397</td>
</tr>
<tr>
<td>2.147</td>
<td>0.081</td>
<td>0.068</td>
<td>0.024</td>
<td>2.38</td>
<td>0.483</td>
</tr>
<tr>
<td>2.152</td>
<td>0.062</td>
<td>0.065</td>
<td>0.035</td>
<td>2.67</td>
<td>0.372</td>
</tr>
<tr>
<td>2.17</td>
<td>0.053</td>
<td>0.047</td>
<td>0.031</td>
<td>2.71</td>
<td>0.377</td>
</tr>
<tr>
<td>2.181</td>
<td>0.052</td>
<td>0.069</td>
<td>0.031</td>
<td>2.38</td>
<td>0.364</td>
</tr>
<tr>
<td>2.14</td>
<td>0.076</td>
<td>0.043</td>
<td>0.017</td>
<td>2.53</td>
<td>0.346</td>
</tr>
<tr>
<td>2.321</td>
<td>0.073</td>
<td>0.045</td>
<td>0.018</td>
<td>2.60</td>
<td>0.451</td>
</tr>
<tr>
<td>2.13</td>
<td>0.061</td>
<td>0.06</td>
<td>0.015</td>
<td>2.35</td>
<td>0.369</td>
</tr>
<tr>
<td>2.149</td>
<td>0.064</td>
<td>0.04</td>
<td>0.015</td>
<td>2.65</td>
<td>0.368</td>
</tr>
<tr>
<td>2.361</td>
<td>0.065</td>
<td>0.045</td>
<td>0.016</td>
<td>2.54</td>
<td>0.424</td>
</tr>
<tr>
<td>2.190</td>
<td>0.065</td>
<td>0.053</td>
<td>0.022</td>
<td>2.525</td>
<td>0.395</td>
</tr>
</tbody>
</table>

<p><em>Note that the results of the Cache strategy are coming just after caching the data set. The first query is ignored as caching is missed.</em></p>
<p>These results were generated from the following environment:</p>
<ul>
<li>Seeded data: 1000 posts and 50 comments for every post.</li>
<li>CPU: AMD Ryzen 5 3600 6-Core Processor 3.60 GHz.</li>
<li>RAM: 32.0 GB.</li>
<li>OS: Windows 10 Pro.</li>
</ul>
<p>To be able to retest these strategies in your environment, follow these steps:</p>
<ul>
<li>Clone this <a target="_blank" href="https://github.com/Mohamed-Mayallo/n_plus_one_problem_benchmarks">repo</a>.</li>
<li>Then run <code>docker-compose up</code>.</li>
<li>For GraphQL, open <code>http://localhost:3000/graphql</code>.</li>
<li><strong>A query suffers from the N+1 problem:</strong> query only <strong><code>commentsWithNPlusOne</code></strong> in the <code>Post</code> type<strong>.</strong></li>
<li><strong>Dataloader strategy</strong>: query only <code>commentsWithDataloader</code> in the <code>Post</code> type.</li>
<li>For REST, follow these endpoints:</li>
<li><strong>A query suffers from the N+1 problem</strong>: <code>http://localhost:3000/api/postsWithNPlusOne</code>.</li>
<li><strong>Eager Loading strategy</strong>: <code>http://localhost:3000/api/postsWithEagerLoading</code>.</li>
<li><strong>Batch Loading strategy</strong>: <code>http://localhost:3000/api/postsWithBatchLoading</code>.</li>
<li><strong>Caching strategy</strong>: <code>http://localhost:3000/api/postsWithCache</code>.</li>
</ul>
<p>My notes about these benchmarks:</p>
<ul>
<li>These strategies are way too efficient.</li>
<li>You may notice that the slower strategy in REST, the Eager Loading strategy, is <strong>about 34 times faster</strong> than the N+1 query in the REST API.</li>
<li>The Dataloader strategy is <strong>about 6.4 times faster</strong> than the N+1 query in the GraphQL API.</li>
<li>If you compared the results of REST and GraphQL APIs, you may notice that REST is faster than GraphQL. I think this is because of the internal implementations of GraphQL, which makes sense.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned that the N+1 query problem is a performance issue you might encounter when working with APIs.</p>
<p>You then learned about some strategies you can follow to avoid this problem like:</p>
<ul>
<li>Eager Loading using SQL Joins</li>
<li>Batch Loading by executing fewer requests and then mapping each corresponding item to its parent.</li>
<li>Caching using Redis</li>
<li>Dataloader in the GraphQL world.</li>
</ul>
<p>Finally, we created some benchmarks about the N+1 query problem so we could see how efficiently these strategies improve our API performance.</p>
<h2 id="heading-before-you-leave">Before you leave</h2>
<p>If you found this article useful, you can <a target="_blank" href="https://mayallo.com/blog/">check out some of my other articles on my personal blog as well</a>.</p>
<p>Thanks a lot for staying with me up till this point. I hope you enjoy reading this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The REST API Handbook – How to Build, Test, Consume, and Document REST APIs ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this tutorial we're going to take a deep dive into REST APIs. I recently wrote this article where I explained the main differences between common API types nowadays. And this tutorial aims to show you an example of how you can fully i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-consume-and-document-a-rest-api/</link>
                <guid isPermaLink="false">66d45eee36c45a88f96b7cd9</guid>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Thu, 27 Apr 2023 13:55:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/pavan-trikutam-71CjSSB83Wo-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this tutorial we're going to take a deep dive into REST APIs.</p>
<p>I recently wrote <a target="_blank" href="https://www.freecodecamp.org/news/rest-vs-graphql-apis/">this article</a> where I explained the main differences between common API types nowadays. And this tutorial aims to show you an example of how you can fully implement a REST API.</p>
<p>We'll cover basic setup and architecture with Node and Express, unit testing with Supertest, seeing how we can consume the API from a React front-end app and finally documenting the API using tools such as Swagger.</p>
<p>Keep in mind we won't go too deep into how each technology works. The goal here is to give you a general overview of how a REST API works, how its pieces interact, and what a full implementation might consist of.</p>
<p>Let's go!</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-rest">What is REST?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-rest-api-with-node-and-express">How to Build a REST API with Node and Express</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-a-rest-api-with-supertest">How to Test a REST API with Supertest</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-consume-a-rest-api-on-a-front-end-react-app">How to Consume a REST API on a Front-end React App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-document-a-rest-api-with-swagger">How to Document a REST API with Swagger</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping up</a></p>
</li>
</ul>
<h1 id="heading-what-is-rest">What is REST?</h1>
<p>Representational State Transfer (REST) is a widely used architectural style for building web services and APIs.</p>
<p>RESTful APIs are designed to be simple, scalable, and flexible. They are often used in web and mobile applications, as well as in Internet of Things (IoT) and microservices architectures.</p>
<p><strong>Main Characteristics:</strong></p>
<ol>
<li><p><strong>Stateless:</strong> REST APIs are stateless, which means that each request contains all the necessary information to process it. This makes it easier to scale the API and improves performance by reducing the need to store and manage session data on the server.</p>
</li>
<li><p><strong>Resource-based:</strong> REST APIs are resource-based, which means that each resource is identified by a unique URI (Uniform Resource Identifier) and can be accessed using standard HTTP methods such as GET, POST, PUT, and DELETE.</p>
</li>
<li><p><strong>Uniform Interface:</strong> REST APIs have a uniform interface that allows clients to interact with resources using a standardized set of methods and response formats. This makes it easier for developers to build and maintain APIs, and for clients to consume them.</p>
</li>
<li><p><strong>Cacheable:</strong> REST APIs are cacheable, which means that responses can be cached to improve performance and reduce network traffic.</p>
</li>
<li><p><strong>Layered System:</strong> REST APIs are designed to be layered, which means that intermediaries such as proxies and gateways can be added between the client and server without affecting the overall system.</p>
</li>
</ol>
<p><strong>Pros</strong> of REST APIs**:**</p>
<ul>
<li><p><strong>Easy to learn and use:</strong> REST APIs are relatively simple and easy to learn compared to other APIs.</p>
</li>
<li><p><strong>Scalability:</strong> The stateless nature of REST APIs makes them highly scalable and efficient.</p>
</li>
<li><p><strong>Flexibility:</strong> REST APIs are flexible and can be used to build a wide range of applications and systems.</p>
</li>
<li><p><strong>Wide support:</strong> REST APIs are widely supported by development tools and frameworks, making it easy to integrate them into existing systems.</p>
</li>
</ul>
<p><strong>Cons</strong> of REST APIs**:**</p>
<ul>
<li><p><strong>Lack of standards:</strong> The lack of strict standards for REST APIs can lead to inconsistencies and interoperability issues.</p>
</li>
<li><p><strong>Limited functionality:</strong> REST APIs are designed to handle simple requests and responses and may not be suitable for more complex use cases.</p>
</li>
<li><p><strong>Security concerns:</strong> REST APIs can be vulnerable to security attacks such as cross-site scripting (XSS) and cross-site request forgery (CSRF) if not implemented properly.</p>
</li>
</ul>
<p><strong>REST APIs are b</strong>est for:****</p>
<ul>
<li><p>REST APIs are well-suited for building web and mobile applications, as well as microservices architectures and IoT systems.</p>
</li>
<li><p>They are particularly useful in situations where scalability and flexibility are important, and where developers need to integrate with existing systems and technologies.</p>
</li>
</ul>
<p>In summary, REST APIs are a popular and widely used architectural style for building web services and APIs. They are simple, scalable, and flexible, and can be used to build a wide range of applications and systems.</p>
<p>While there are some limitations and concerns with REST APIs, they remain a popular and effective option for building APIs in many different industries and sectors.</p>
<h1 id="heading-how-to-build-a-rest-api-with-node-and-express">How to Build a REST API with Node and Express</h1>
<h2 id="heading-our-tools">Our tools</h2>
<p><a target="_blank" href="https://nodejs.org/"><strong>Node.js</strong></a> is an open-source, cross-platform, back-end JavaScript runtime environment that allows developers to execute JavaScript code outside of a web browser. It was created by Ryan Dahl in 2009 and has since become a popular choice for building web applications, APIs, and servers.</p>
<p>Node.js provides an event-driven, non-blocking I/O model that makes it lightweight and efficient, allowing it to handle large amounts of data with high performance. It also has a large and active community, with many libraries and modules available to help developers build their applications more quickly and easily.</p>
<p><a target="_blank" href="https://expressjs.com/"><strong>Express.js</strong></a> is a popular web application framework for Node.js, which is used to build web applications and APIs. It provides a set of features and tools for building web servers, handling HTTP requests and responses, routing requests to specific handlers, handling middleware, and much more.</p>
<p>Express is known for its simplicity, flexibility, and scalability, making it a popular choice for developers building web applications with Node.js.</p>
<p>Some of the key features and benefits of Express.js include:</p>
<ul>
<li><p><strong>Minimalistic and flexible:</strong> Express.js provides a minimalistic and flexible structure that allows developers to build applications the way they want to.</p>
</li>
<li><p><strong>Routing:</strong> Express.js makes it easy to define routes for handling HTTP requests and mapping them to specific functions or handlers.</p>
</li>
<li><p><strong>Middleware:</strong> Express.js allows developers to define middleware functions that can be used to handle common tasks such as authentication, logging, error handling, and more.</p>
</li>
<li><p><strong>Robust API:</strong> Express.js provides a robust API for handling HTTP requests and responses, allowing developers to build high-performance web applications.</p>
</li>
</ul>
<h2 id="heading-our-architecture">Our architecture</h2>
<p>For this project we'll follow a layers architecture in our codebase. Layers architecture is about dividing concerns and responsibilities into different folders and files, and allowing direct communication only between certain folders and files.</p>
<p>The matter of how many layers should your project have, what names should each layer have, and what actions should it handle is all a matter of discussion. So let's see what I think is a good approach for our example.</p>
<p>Our application will have five different layers, which will be ordered in this way:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-110.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Application layers</em></p>
<ul>
<li><p>The application layer will have the basic setup of our server and the connection to our routes (the next layer).</p>
</li>
<li><p>The routes layer will have the definition of all of our routes and the connection to the controllers (the next layer).</p>
</li>
<li><p>The controllers layer will have the actual logic we want to perform in each of our endpoints and the connection to the model layer (the next layer, you get the idea...)</p>
</li>
<li><p>The model layer will hold the logic for interacting with our mock database.</p>
</li>
<li><p>Finally, the persistence layer is where our database will be.</p>
</li>
</ul>
<p>An important thing to keep in mind is that in these kinds of architectures, <strong>there's a defined communication flow</strong> between the layers that has to be followed for it to make sense.</p>
<p>This means that a request first has to go through the first layer, then the second, then the third and so on. No request should skip layers because that would mess with the logic of the architecture and the benefits of organization and modularity it gives us.</p>
<blockquote>
<p>If you'd like to know some other API architecture options, I recommend <a target="_blank" href="https://www.freecodecamp.org/news/an-introduction-to-software-architecture-patterns/">you this software architecture article</a> I wrote a while ago.</p>
</blockquote>
<h2 id="heading-the-code">The code</h2>
<p>Before jumping to the code, let's mention what we'll actually build. We'll be building an API for a pet shelter business. This pet shelter needs to register the pets that are staying in the shelter, and for that we'll perform basic CRUD operations (create, read, update and delete).</p>
<p>Now yeah, let's get this thing going. Create a new directory, hop on to it and start a new Node project by running <code>npm init -y</code>.</p>
<p>Then install Express by running <code>npm i express</code> and install nodemon as a dev dependency by running <code>npm i -D nodemon</code> (<a target="_blank" href="https://nodemon.io/">Nodemon</a> is a tool we'll use to get our server running and test it). Lastly, also run <code>npm i cors</code>, which we'll use to be able to test our server locally.</p>
<h3 id="heading-appjs">App.js</h3>
<p>Cool, now create an <code>app.js</code> file and drop this code in it:</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> cors <span class="hljs-keyword">from</span> <span class="hljs-string">'cors'</span>

<span class="hljs-keyword">import</span> petRoutes <span class="hljs-keyword">from</span> <span class="hljs-string">'./pets/routes/pets.routes.js'</span>

<span class="hljs-keyword">const</span> app = express()
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>

<span class="hljs-comment">/* Global middlewares */</span>
app.use(cors())
app.use(express.json())

<span class="hljs-comment">/* Routes */</span>
app.use(<span class="hljs-string">'/pets'</span>, petRoutes)

<span class="hljs-comment">/* Server setup */</span>
<span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'test'</span>) {
    app.listen(port, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`⚡️[server]: Server is running at https://localhost:<span class="hljs-subst">${port}</span>`</span>))
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app
</code></pre>
<p>This would be the <strong>application layer</strong> of our project.</p>
<p>Here we're basically setting up our server and declaring that any request that hits the <code>/pets</code> direction should use the routes (endpoints) we have declared in the <code>./pets/routes/pets.routes.js</code> directory.</p>
<p>Next, go ahead and create this folder structure in your project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-246.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Folder structure</em></p>
<h3 id="heading-routes">Routes</h3>
<p>Hop on to the routes folder, create a file called <code>pets.routes.js</code>, and drop this code in it:</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> {
  listPets,
  getPet,
  editPet,
  addPet,
  deletePet,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../controllers/pets.controllers.js"</span>;

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

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

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

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

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

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

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>In this file we're initializing a router (the thing that processes our request and directs them accordingly given the endpoint URL) and setting up each of our endpoints.</p>
<p>See that for each endpoint we declare the corresponding HTTP method (<code>get</code>, <code>put</code>, and so on) and the corresponding function that that endpoint will trigger (<code>listPets</code>, <code>getPet</code>, and so on). Each function name is quite explicit so we can easily know what each endpoint does without needing to see further code. ;)</p>
<p>Lastly, we also declare which endpoint will receive URL parameters on the requests like this: <code>router.get("/:id", getPet);</code> Here we're saying that we'll receive the <code>id</code> of the pet as an URL parameter.</p>
<h3 id="heading-controllers">Controllers</h3>
<p>Now go to the controllers folder, create a <code>pets.controllers.js</code> file, and put this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getItem, listItems, editItem, addItem, deleteItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'../models/pets.models.js'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPet = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = getItem(<span class="hljs-built_in">parseInt</span>(req.params.id))
        res.status(<span class="hljs-number">200</span>).json(resp)

    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).send(err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> listPets = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = listItems()
        res.status(<span class="hljs-number">200</span>).json(resp)

    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).send(err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editPet = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = editItem(<span class="hljs-built_in">parseInt</span>(req.params.id), req.body)
        res.status(<span class="hljs-number">200</span>).json(resp)

    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).send(err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addPet = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = addItem(req.body)
        res.status(<span class="hljs-number">200</span>).json(resp)

    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).send(err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deletePet = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> resp = deleteItem(<span class="hljs-built_in">parseInt</span>(req.params.id))
        res.status(<span class="hljs-number">200</span>).json(resp)

    } <span class="hljs-keyword">catch</span> (err) {
        res.status(<span class="hljs-number">500</span>).send(err)
    }
}
</code></pre>
<p>Controllers are the functions that each endpoint request will trigger. As you can see, they receive as parameters the request and response objects. In the request object we can read things such as URL or body parameters, and we'll use the response object to send our response after doing the corresponding computation.</p>
<p>Each controller calls a specific function defined in our models.</p>
<h3 id="heading-models">Models</h3>
<p>Now go to the models folder and create a <code>pets.models.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> db <span class="hljs-keyword">from</span> <span class="hljs-string">'../../db/db.js'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getItem = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> pet = db?.pets?.filter(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet?.id === id)[<span class="hljs-number">0</span>]
        <span class="hljs-keyword">return</span> pet
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error'</span>, err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> listItems = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">return</span> db?.pets
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error'</span>, err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> editItem = <span class="hljs-function">(<span class="hljs-params">id, data</span>) =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> index = db.pets.findIndex(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet.id === id)

        <span class="hljs-keyword">if</span> (index === <span class="hljs-number">-1</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Pet not found'</span>)
        <span class="hljs-keyword">else</span> {
            db.pets[index] = data
            <span class="hljs-keyword">return</span> db.pets[index]
        }        
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error'</span>, err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addItem = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {  
        <span class="hljs-keyword">const</span> newPet = { <span class="hljs-attr">id</span>: db.pets.length + <span class="hljs-number">1</span>, ...data }
        db.pets.push(newPet)
        <span class="hljs-keyword">return</span> newPet

    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error'</span>, err)
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteItem = <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// delete item from db</span>
        <span class="hljs-keyword">const</span> index = db.pets.findIndex(<span class="hljs-function"><span class="hljs-params">pet</span> =&gt;</span> pet.id === id)

        <span class="hljs-keyword">if</span> (index === <span class="hljs-number">-1</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Pet not found'</span>)
        <span class="hljs-keyword">else</span> {
            db.pets.splice(index, <span class="hljs-number">1</span>)
            <span class="hljs-keyword">return</span> db.pets
        }
    } <span class="hljs-keyword">catch</span> (error) {

    }
}
</code></pre>
<p>These are the functions responsible for interacting with our data layer (database) and returning the corresponding information to our controllers.</p>
<h3 id="heading-database">Database</h3>
<p>We wont use a real database for this example. Instead we'll just use a simple array that will work just fine for example purposes, though our data will of course reset every time our server does.</p>
<p>In the root of our project, create a <code>db</code> folder and a <code>db.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> db = {
    <span class="hljs-attr">pets</span>: [
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>,
        },
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Fido'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'poodle'</span>,
        },
        {
            <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>,
        },
    ]
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> db
</code></pre>
<p>As you can see, our <code>db</code> object contains a <code>pets</code> property whose value is an array of objects, each object being a pet. For each pet, we store an id, name, type, age and breed.</p>
<p>Now go to your terminal and run <code>nodemon app.js</code>. You should see this message confirming your server is alive: <code>⚡️[server]: Server is running at [https://localhost:3000](https://localhost:3000)</code>.</p>
<h1 id="heading-how-to-test-a-rest-api-with-supertest">How to Test a REST API with Supertest</h1>
<p>Now that our server is up and running, let's implement a simple test suit to check if each of our endpoints behaves as expected.</p>
<p>If you're not familiar with automated testing, I recommend you read <a target="_blank" href="https://www.freecodecamp.org/news/test-a-react-app-with-jest-testing-library-and-cypress/">this introductory article I wrote a while ago</a>.</p>
<h2 id="heading-our-tools-1">Our tools</h2>
<p><a target="_blank" href="https://www.npmjs.com/package/supertest"><strong>SuperTest</strong></a> is a JavaScript library that is used for testing HTTP servers or web applications that make HTTP requests. It provides a high-level abstraction for testing HTTP, allowing developers to send HTTP requests and make assertions about the responses received, making it easier to write automated tests for web applications.</p>
<p>SuperTest works with any JavaScript testing framework, such as <a target="_blank" href="https://mochajs.org/">Mocha</a> or <a target="_blank" href="https://jestjs.io/">Jest</a>, and can be used with any HTTP server or web application framework, such as Express.</p>
<p>SuperTest is built on top of the popular testing library Mocha, and uses the <a target="_blank" href="https://www.chaijs.com/">Chai</a> assertion library to make assertions about the responses received. It provides an easy-to-use API for making HTTP requests, including support for authentication, headers, and request bodies.</p>
<p>SuperTest also allows developers to test the entire request/response cycle, including middleware and error handling, making it a powerful tool for testing web applications.</p>
<p>Overall, SuperTest is a valuable tool for developers who want to write automated tests for their web applications. It helps ensure that their applications are functioning correctly and that any changes they make to the codebase do not introduce new bugs or issues.</p>
<h2 id="heading-the-code-1">The code</h2>
<p>First we'll need to install some dependencies. To save up terminal commands, go to your <code>package.json</code> file and replace your <code>devDependencies</code> section with this. Then run <code>npm install</code></p>
<pre><code class="lang-javascript">  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"@babel/core"</span>: <span class="hljs-string">"^7.21.4"</span>,
    <span class="hljs-string">"@babel/preset-env"</span>: <span class="hljs-string">"^7.21.4"</span>,
    <span class="hljs-string">"babel-jest"</span>: <span class="hljs-string">"^29.5.0"</span>,
    <span class="hljs-string">"jest"</span>: <span class="hljs-string">"^29.5.0"</span>,
    <span class="hljs-string">"jest-babel"</span>: <span class="hljs-string">"^1.0.1"</span>,
    <span class="hljs-string">"nodemon"</span>: <span class="hljs-string">"^2.0.22"</span>,
    <span class="hljs-string">"supertest"</span>: <span class="hljs-string">"^6.3.3"</span>
  }
</code></pre>
<p>Here we're installing the <code>supertest</code> and <code>jest</code> libraries, which we need for our tests to run, plus some <code>babel</code> stuff we need for our project to correctly identify which files are test files.</p>
<p>Still in your <code>package.json</code>, add this script:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"jest"</span>
  },
</code></pre>
<p>To end with the boilerplate, in the root of your project, create a <code>babel.config.cjs</code> file and drop this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//babel.config.cjs</span>
<span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">presets</span>: [
      [
        <span class="hljs-string">'@babel/preset-env'</span>,
        {
          <span class="hljs-attr">targets</span>: {
            <span class="hljs-attr">node</span>: <span class="hljs-string">'current'</span>,
          },
        },
      ],
    ],
  };
</code></pre>
<p>Now let's write some actual tests! Within your routes folder, create a <code>pets.test.js</code> file with this code in it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> supertest <span class="hljs-keyword">from</span> <span class="hljs-string">'supertest'</span> <span class="hljs-comment">// Import supertest</span>
<span class="hljs-keyword">import</span> server <span class="hljs-keyword">from</span> <span class="hljs-string">'../../app'</span> <span class="hljs-comment">// Import the server object</span>
<span class="hljs-keyword">const</span> requestWithSupertest = supertest(server) <span class="hljs-comment">// We will use this function to mock HTTP requests</span>

describe(<span class="hljs-string">'GET "/"'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'GET "/" returns all pets'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> requestWithSupertest.get(<span class="hljs-string">'/pets'</span>)
        expect(res.status).toEqual(<span class="hljs-number">200</span>)
        expect(res.type).toEqual(expect.stringContaining(<span class="hljs-string">'json'</span>))
        expect(res.body).toEqual([
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>,
            },
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Fido'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'poodle'</span>,
            },
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>,
            },
        ])
    })
})

describe(<span class="hljs-string">'GET "/:id"'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'GET "/:id" returns given pet'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> requestWithSupertest.get(<span class="hljs-string">'/pets/1'</span>)
        expect(res.status).toEqual(<span class="hljs-number">200</span>)
        expect(res.type).toEqual(expect.stringContaining(<span class="hljs-string">'json'</span>))
        expect(res.body).toEqual(
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Rex'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'dog'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'labrador'</span>,
            }
        )
    })
})

describe(<span class="hljs-string">'PUT "/:id"'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'PUT "/:id" updates pet and returns it'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> requestWithSupertest.put(<span class="hljs-string">'/pets/1'</span>).send({
            <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
        })
        expect(res.status).toEqual(<span class="hljs-number">200</span>)
        expect(res.type).toEqual(expect.stringContaining(<span class="hljs-string">'json'</span>))
        expect(res.body).toEqual({
            <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
        })
    })
})

describe(<span class="hljs-string">'POST "/"'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'POST "/" adds new pet and returns the added item'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> requestWithSupertest.post(<span class="hljs-string">'/pets'</span>).send({
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
        })
        expect(res.status).toEqual(<span class="hljs-number">200</span>)
        expect(res.type).toEqual(expect.stringContaining(<span class="hljs-string">'json'</span>))
        expect(res.body).toEqual({
            <span class="hljs-attr">id</span>: <span class="hljs-number">4</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
            <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
            <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
            <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
        })
    })
})

describe(<span class="hljs-string">'DELETE "/:id"'</span>, <span class="hljs-function">() =&gt;</span> {
    test(<span class="hljs-string">'DELETE "/:id" deletes given pet and returns updated list'</span>, <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> requestWithSupertest.delete(<span class="hljs-string">'/pets/2'</span>)
        expect(res.status).toEqual(<span class="hljs-number">200</span>)
        expect(res.type).toEqual(expect.stringContaining(<span class="hljs-string">'json'</span>))
        expect(res.body).toEqual([
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Rexo'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'dogo'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">4</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'doberman'</span>
            },
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Mittens'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'tabby'</span>,
            },
            {
                <span class="hljs-attr">id</span>: <span class="hljs-number">4</span>,
                <span class="hljs-attr">name</span>: <span class="hljs-string">'Salame'</span>,
                <span class="hljs-attr">type</span>: <span class="hljs-string">'cat'</span>,
                <span class="hljs-attr">age</span>: <span class="hljs-number">6</span>,
                <span class="hljs-attr">breed</span>: <span class="hljs-string">'pinky'</span>
            }
        ])
    })
})
</code></pre>
<p>For each endpoint, the tests send HTTP requests and check the responses for three things: the HTTP status code, the response type (which should be JSON), and the response body (which should match the expected JSON format).</p>
<ul>
<li><p>The first test sends a GET request to the /pets endpoint and expects the API to return an array of pets in JSON format.</p>
</li>
<li><p>The second test sends a GET request to the /pets/:id endpoint and expects the API to return the pet with the specified ID in JSON format.</p>
</li>
<li><p>The third test sends a PUT request to the /pets/:id endpoint and expects the API to update the pet with the specified ID and return the updated pet in JSON format.</p>
</li>
<li><p>The fourth test sends a POST request to the /pets endpoint and expects the API to add a new pet and return the added pet in JSON format.</p>
</li>
<li><p>Finally, the fifth test sends a DELETE request to the /pets/:id endpoint and expects the API to remove the pet with the specified ID and return the updated list of pets in JSON format.</p>
</li>
</ul>
<p>Each test checks whether the expected HTTP status code, response type, and response body are returned. If any of these expectations are not met, the test fails and provides an error message.</p>
<p>These tests are important for ensuring that the API is working correctly and consistently across different HTTP requests and endpoints. The tests can be run automatically, which makes it easy to detect any issues or regressions in the API's functionality.</p>
<p>Now go to your terminal, run <code>npm test</code>, and you should see all your tests passing:</p>
<pre><code class="lang-javascript">&gt; restapi@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span> test
&gt; jest

 PASS  pets/routes/pets.test.js
  GET <span class="hljs-string">"/"</span>
    ✓ GET <span class="hljs-string">"/"</span> returns all pets (<span class="hljs-number">25</span> ms)
  GET <span class="hljs-string">"/:id"</span>
    ✓ GET <span class="hljs-string">"/:id"</span> returns given pet (<span class="hljs-number">4</span> ms)
  PUT <span class="hljs-string">"/:id"</span>
    ✓ PUT <span class="hljs-string">"/:id"</span> updates pet and returns it (<span class="hljs-number">15</span> ms)
  POST <span class="hljs-string">"/"</span>
    ✓ POST <span class="hljs-string">"/"</span> adds <span class="hljs-keyword">new</span> pet and returns the added item (<span class="hljs-number">3</span> ms)
  DELETE <span class="hljs-string">"/:id"</span>
    ✓ DELETE <span class="hljs-string">"/:id"</span> deletes given pet and returns updated list (<span class="hljs-number">3</span> ms)

Test Suites: <span class="hljs-number">1</span> passed, <span class="hljs-number">1</span> total
<span class="hljs-attr">Tests</span>:       <span class="hljs-number">5</span> passed, <span class="hljs-number">5</span> total
<span class="hljs-attr">Snapshots</span>:   <span class="hljs-number">0</span> total
<span class="hljs-attr">Time</span>:        <span class="hljs-number">1.611</span> s
Ran all test suites.
</code></pre>
<h1 id="heading-how-to-consume-a-rest-api-on-a-front-end-react-app">How to Consume a REST API on a Front-end React App</h1>
<p>Now we know our server is running and our endpoints are behaving as expected. Let's see some more realistic example of how our API might be consumed by a front end app.</p>
<p>For this example, we'll use a React application, and two different tools to send and process our requests: the Fetch API and the Axios library.</p>
<h2 id="heading-our-tools-2">Our tools</h2>
<p><a target="_blank" href="https://react.dev/"><strong>React</strong></a> is a popular JavaScript library for building user interfaces. It allows developers to create reusable UI components and efficiently update and render them in response to changes in application state.</p>
<p>The <strong>Fetch API</strong> is a modern browser API that allows developers to make asynchronous HTTP requests from client-side JavaScript code. It provides a simple interface for fetching resources across the network, and supports a variety of request and response types.</p>
<p><a target="_blank" href="https://axios-http.com/docs/intro"><strong>Axios</strong></a> is a popular HTTP client library for JavaScript. It provides a simple and intuitive API for making HTTP requests, and supports a wide range of features, including request and response interception, automatic transforms for request and response data, and the ability to cancel requests. It can be used both in the browser and on the server, and is often used in conjunction with React applications.</p>
<h2 id="heading-the-code-2">The code</h2>
<p>Let's create our React app by running <code>yarn create vite</code> and following the terminal prompts. Once that's done, run <code>yarn add axios</code> and <code>yarn add react-router-dom</code> (which we'll use to setup basic routing in our app).</p>
<h3 id="heading-appjsx">App.jsx</h3>
<p>Put this code within your <code>App.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Suspense, lazy, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">const</span> PetList = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span> (<span class="hljs-string">'./pages/PetList'</span>))
<span class="hljs-keyword">const</span> PetDetail = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span> (<span class="hljs-string">'./pages/PetDetail'</span>))
<span class="hljs-keyword">const</span> EditPet = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span> (<span class="hljs-string">'./pages/EditPet'</span>))
<span class="hljs-keyword">const</span> AddPet = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span> (<span class="hljs-string">'./pages/AddPet'</span>))

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

  <span class="hljs-keyword">const</span> [petToEdit, setPetToEdit] = useState(<span class="hljs-literal">null</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">Router</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Pet shelter<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">'/add'</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add new pet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">'/'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;<span class="hljs-tag">&lt;<span class="hljs-name">PetList</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>}/&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">'/:petId'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;<span class="hljs-tag">&lt;<span class="hljs-name">PetDetail</span> <span class="hljs-attr">setPetToEdit</span>=<span class="hljs-string">{setPetToEdit}</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>}/&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">'/:petId/edit'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;<span class="hljs-tag">&lt;<span class="hljs-name">EditPet</span> <span class="hljs-attr">petToEdit</span>=<span class="hljs-string">{petToEdit}</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>}/&gt;</span>

          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">'/add'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span>}&gt;<span class="hljs-tag">&lt;<span class="hljs-name">AddPet</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>}/&gt;
        &lt;/Routes&gt;

      &lt;/Router&gt;
    &lt;/div&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>Here we're just defining our routes. We'll have 4 main routes in our app, each corresponding to a different view:</p>
<ul>
<li><p>One to see the whole list of pets.</p>
</li>
<li><p>One to see the detail of a single pet.</p>
</li>
<li><p>One to edit a single pet.</p>
</li>
<li><p>One to add a new pet to the list.</p>
</li>
</ul>
<p>Besides, we have a button to add a new pet and a state that will store the information of the pet we want to edit.</p>
<p>Next, create a <code>pages</code> directory with these files in it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-281.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Folder structure</em></p>
<h3 id="heading-petlistjsx">PetList.jsx</h3>
<p>Let's start with the file responsible for rendering the whole list of pets:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PetList</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [pets, setPets] = useState([])

    <span class="hljs-keyword">const</span> getPets = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">/* FETCH */</span>
            <span class="hljs-comment">// const response = await fetch('http://localhost:3000/pets')</span>
            <span class="hljs-comment">// const data = await response.json()</span>
            <span class="hljs-comment">// if (response.status === 200) setPets(data)</span>

            <span class="hljs-comment">/* AXIOS */</span>
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'http://localhost:3000/pets'</span>)
            <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) setPets(response.data)

        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error'</span>, error)
        }
    }

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

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Pet List<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            {pets?.map((pet) =&gt; {
                return (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{pet?.id}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{pet?.name} - {pet?.type} - {pet?.breed}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>`/${<span class="hljs-attr">pet</span>?<span class="hljs-attr">.id</span>}`}&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Pet detail<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                )
            })}
        <span class="hljs-tag">&lt;/&gt;</span></span>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PetList
</code></pre>
<p>As you can see, logic-wise we have 3 main things here:</p>
<ul>
<li><p>A state that stores the list of pets to render.</p>
</li>
<li><p>A function that executes the corresponding request to our API.</p>
</li>
<li><p>A useEffect that executes that function when the component renders.</p>
</li>
</ul>
<p>You can see that the syntax for making the HTTP request with fetch and Axios is rather similar, but Axios is a tiny bit more succinct. Once we make the request, we check if the status is 200 (meaning it was successful), and store the response in our state.</p>
<p>Once our state is updated, the component will render the data provided by our API.</p>
<blockquote>
<p>Remember that to make calls to our server, we must have it up and running by running <code>nodemon app.js</code> in our server project terminal.</p>
</blockquote>
<h3 id="heading-petdetailjsx">PetDetail.jsx</h3>
<p>Now let's go to the <code>PetDetail.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { useParams, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PetDetail</span>(<span class="hljs-params">{ setPetToEdit }</span>) </span>{

    <span class="hljs-keyword">const</span> [pet, setPet] = useState([])

    <span class="hljs-keyword">const</span> { petId } = useParams()

    <span class="hljs-keyword">const</span> getPet = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">/* FETCH */</span>
            <span class="hljs-comment">// const response = await fetch(`http://localhost:3000/pets/${petId}`)</span>
            <span class="hljs-comment">// const data = await response.json()</span>
            <span class="hljs-comment">// if (response.status === 200) {</span>
            <span class="hljs-comment">//     setPet(data)</span>
            <span class="hljs-comment">//     setPetToEdit(data)</span>
            <span class="hljs-comment">// }</span>

            <span class="hljs-comment">/* AXIOS */</span>
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">`http://localhost:3000/pets/<span class="hljs-subst">${petId}</span>`</span>)
            <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
                setPet(response.data)
                setPetToEdit(response.data)
            }

        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error'</span>, error)
        }
    }

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

    <span class="hljs-keyword">const</span> deletePet = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">/* FETCH */</span>
            <span class="hljs-comment">// const response = await fetch(`http://localhost:3000/pets/${petId}`, {</span>
            <span class="hljs-comment">//     method: 'DELETE'</span>
            <span class="hljs-comment">// })</span>

            <span class="hljs-comment">/* AXIOS */</span>
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`http://localhost:3000/pets/<span class="hljs-subst">${petId}</span>`</span>)

            <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">'/'</span>
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error'</span>, error)
        }
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Pet Detail<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            {pet &amp;&amp; (
                <span class="hljs-tag">&lt;&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet name: {pet.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet type: {pet.type}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet age: {pet.age}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Pet breed: {pet.breed}<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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>`/${<span class="hljs-attr">pet</span>?<span class="hljs-attr">.id</span>}/<span class="hljs-attr">edit</span>`}&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginRight:</span> <span class="hljs-attr">10</span> }}&gt;</span>Edit pet<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>

                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginLeft:</span> <span class="hljs-attr">10</span> }}
                            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deletePet()}
                        &gt;
                            Delete pet
                        <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;/&gt;</span></span>
            )}
        &lt;/div&gt;
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> PetDetail
</code></pre>
<p>Here we have two different kind of requests:</p>
<ul>
<li><p>One that gets the information of the given pet (which behaves very similar to the previous request we saw). The only difference here is we're passing an URL parameter to our endpoint, which at the same time we're reading from the URL in our front-end app.</p>
</li>
<li><p>The other request is to delete the given pet from our register. The difference here is once we confirm that the request was successful, we redirect the user to the root of our app.</p>
</li>
</ul>
<h3 id="heading-addpetjsx">AddPet.jsx</h3>
<p>This is the file responsible for adding a new pet to our register:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddPet</span>(<span class="hljs-params"></span>) </span>{

    <span class="hljs-keyword">const</span> [petName, setPetName] = useState()
    <span class="hljs-keyword">const</span> [petType, setPetType] = useState()
    <span class="hljs-keyword">const</span> [petAge, setPetAge] = useState()
    <span class="hljs-keyword">const</span> [petBreed, setPetBreed] = useState()

    <span class="hljs-keyword">const</span> addPet = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> petData = {
                <span class="hljs-attr">name</span>: petName,
                <span class="hljs-attr">type</span>: petType,
                <span class="hljs-attr">age</span>: petAge,
                <span class="hljs-attr">breed</span>: petBreed
            }

            <span class="hljs-comment">/* FETCH */</span>
            <span class="hljs-comment">// const response = await fetch('http://localhost:3000/pets/', {</span>
            <span class="hljs-comment">//     method: 'POST',</span>
            <span class="hljs-comment">//     headers: {</span>
            <span class="hljs-comment">//         'Content-Type': 'application/json'</span>
            <span class="hljs-comment">//     },</span>
            <span class="hljs-comment">//     body: JSON.stringify(petData)</span>
            <span class="hljs-comment">// })</span>

            <span class="hljs-comment">// if (response.status === 200) {</span>
            <span class="hljs-comment">//     const data = await response.json()</span>
            <span class="hljs-comment">//     window.location.href = `/${data.id}`</span>
            <span class="hljs-comment">// }</span>

            <span class="hljs-comment">/* AXIOS */</span>
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(
                <span class="hljs-string">'http://localhost:3000/pets/'</span>,
                petData,
                { <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> } }
            )

            <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`/<span class="hljs-subst">${response.data.id}</span>`</span>

        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error'</span>, error)
        }
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Add Pet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet name<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">value</span>=<span class="hljs-string">{petName}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetName(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet type<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">value</span>=<span class="hljs-string">{petType}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetType(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet age<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">value</span>=<span class="hljs-string">{petAge}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetAge(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet breed<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">value</span>=<span class="hljs-string">{petBreed}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetBreed(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">button</span>
                <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">30</span> }}
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> addPet()}
            &gt;
                Add pet
            <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>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AddPet
</code></pre>
<p>Here we're rendering a form in which the user has to enter the new pet info.</p>
<p>We have a state for each piece of information to enter, and in our request we build an object with each state. This object will be the body of our request.</p>
<p>On our request, we check if the response is successful. If it is, we redirect to the detail page of the newly added pet. To redirect, we use the <code>id</code> returned in the HTTP response. ;)</p>
<h3 id="heading-editpetjsx">EditPet.jsx</h3>
<p>Finally, the file responsible for editing a pet register:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EditPet</span>(<span class="hljs-params">{ petToEdit }</span>) </span>{

    <span class="hljs-keyword">const</span> [petName, setPetName] = useState(petToEdit?.name)
    <span class="hljs-keyword">const</span> [petType, setPetType] = useState(petToEdit?.type)
    <span class="hljs-keyword">const</span> [petAge, setPetAge] = useState(petToEdit?.age)
    <span class="hljs-keyword">const</span> [petBreed, setPetBreed] = useState(petToEdit?.breed)

    <span class="hljs-keyword">const</span> editPet = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> petData = {
                <span class="hljs-attr">id</span>: petToEdit.id,
                <span class="hljs-attr">name</span>: petName,
                <span class="hljs-attr">type</span>: petType,
                <span class="hljs-attr">age</span>: petAge,
                <span class="hljs-attr">breed</span>: petBreed
            }

            <span class="hljs-comment">/* FETCH */</span>
            <span class="hljs-comment">// const response = await fetch(`http://localhost:3000/pets/${petToEdit.id}`, {</span>
            <span class="hljs-comment">//     method: 'PUT',</span>
            <span class="hljs-comment">//     headers: {</span>
            <span class="hljs-comment">//         'Content-Type': 'application/json'</span>
            <span class="hljs-comment">//     },</span>
            <span class="hljs-comment">//     body: JSON.stringify(petData)</span>
            <span class="hljs-comment">// })</span>

            <span class="hljs-comment">/* AXIOS */</span>
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.put(
                <span class="hljs-string">`http://localhost:3000/pets/<span class="hljs-subst">${petToEdit.id}</span>`</span>,
                petData,
                { <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> } }
            )

            <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
                <span class="hljs-built_in">window</span>.location.href = <span class="hljs-string">`/<span class="hljs-subst">${petToEdit.id}</span>`</span>
            }
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'error'</span>, error)
        }
    }

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">center</span>', <span class="hljs-attr">aligniItems:</span> '<span class="hljs-attr">center</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Edit Pet<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet name<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">value</span>=<span class="hljs-string">{petName}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetName(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet type<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">value</span>=<span class="hljs-string">{petType}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetType(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet age<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">value</span>=<span class="hljs-string">{petAge}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetAge(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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">flexDirection:</span> '<span class="hljs-attr">column</span>', <span class="hljs-attr">margin:</span> <span class="hljs-attr">20</span> }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>Pet breed<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">value</span>=<span class="hljs-string">{petBreed}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setPetBreed(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">button</span>
                <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> <span class="hljs-attr">30</span> }}
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> editPet()}
            &gt;
                Save changes
            <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>
    )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> EditPet
</code></pre>
<p>This behaves very similar to the <code>AddPet.jsx</code> file. The only difference is that our pet info states are initialized with the values of the pet we want to edit. When those values are updated by the user, we construct an object that will be our request body and send the request with the updated information. Quite straightforward. ;)</p>
<p>And that's it! We're using all of our API endpoints in our front end app. =)</p>
<h1 id="heading-how-to-document-a-rest-api-with-swagger">How to Document a REST API with Swagger</h1>
<p>Now that we have our server up and running, tested, and connected to our front end app, the last step in our implementation will be to document our API.</p>
<p>Documenting and API generally means declaring which endpoints are available, what actions are performed by each endpoint, and the parameters and return values for each of them.</p>
<p>This is useful not only to remember how our server works, but also for people who want to interact with our API.</p>
<p>For example, in companies it's very usual to have back-end teams and front-end teams. When an API is being developed and needs to be integrated with a front-end app, it would be very tedious to ask which endpoint does what, and what parameters should be passed. If you have all that info in a singe place, you can just go there and read it yourself. That's what documentation is.</p>
<h2 id="heading-our-tools-3">Our tools</h2>
<p><a target="_blank" href="https://swagger.io/"><strong>Swagger</strong></a> is a set of open-source tools that help developers build, document, and consume RESTful web services. It provides a user-friendly graphical interface for users to interact with an API and also generates client code for various programming languages to make API integration easier.</p>
<p>Swagger provides a comprehensive set of features for API development, including API design, documentation, testing, and code generation. It allows developers to define API endpoints, input parameters, expected output, and authentication requirements in a standardized way using the OpenAPI specification.</p>
<p>Swagger UI is a popular tool that renders OpenAPI specifications as an interactive API documentation that allows developers to explore and test APIs through a web browser. It provides a user-friendly interface that allows developers to easily view and interact with API endpoints.</p>
<h2 id="heading-how-to-implement-swagger">How to Implement Swagger</h2>
<p>Back in our server app, to implement Swagger we'll need two new dependencies. So run <code>npm i swagger-jsdoc</code> and <code>npm i swagger-ui-express</code>.</p>
<p>Next, modify the <code>app.js</code> file to 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> cors <span class="hljs-keyword">from</span> <span class="hljs-string">'cors'</span>
<span class="hljs-keyword">import</span> swaggerUI <span class="hljs-keyword">from</span> <span class="hljs-string">'swagger-ui-express'</span>
<span class="hljs-keyword">import</span> swaggerJSdoc <span class="hljs-keyword">from</span> <span class="hljs-string">'swagger-jsdoc'</span>

<span class="hljs-keyword">import</span> petRoutes <span class="hljs-keyword">from</span> <span class="hljs-string">'./pets/routes/pets.routes.js'</span>

<span class="hljs-keyword">const</span> app = express()
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>

<span class="hljs-comment">// swagger definition</span>
<span class="hljs-keyword">const</span> swaggerSpec = {
    <span class="hljs-attr">definition</span>: {
        <span class="hljs-attr">openapi</span>: <span class="hljs-string">'3.0.0'</span>,
        <span class="hljs-attr">info</span>: {
            <span class="hljs-attr">title</span>: <span class="hljs-string">'Pets API'</span>,
            <span class="hljs-attr">version</span>: <span class="hljs-string">'1.0.0'</span>,
        },
        <span class="hljs-attr">servers</span>: [
            {
                <span class="hljs-attr">url</span>: <span class="hljs-string">`http://localhost:<span class="hljs-subst">${port}</span>`</span>,
            }
        ]
    },
    <span class="hljs-attr">apis</span>: [<span class="hljs-string">'./pets/routes/*.js'</span>],
}

<span class="hljs-comment">/* Global middlewares */</span>
app.use(cors())
app.use(express.json())
app.use(
    <span class="hljs-string">'/api-docs'</span>,
    swaggerUI.serve,
    swaggerUI.setup(swaggerJSdoc(swaggerSpec))
)

<span class="hljs-comment">/* Routes */</span>
app.use(<span class="hljs-string">'/pets'</span>, petRoutes)

<span class="hljs-comment">/* Server setup */</span>
<span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'test'</span>) {
    app.listen(port, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`⚡️[server]: Server is running at https://localhost:<span class="hljs-subst">${port}</span>`</span>))
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> app
</code></pre>
<p>As you can see, we're importing the new dependencies, we're creating a <code>swaggerSpec</code> object that contains config options for our implementation, and then setting a middleware to render our documentation in the <code>/api-docs</code> directory of our app.</p>
<p>By now, if you open your browser and go to <a target="_blank" href="http://localhost:3000/api-docs/"><code>http://localhost:3000/api-docs/</code></a> you should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-325.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Documentation UI</em></p>
<p>The cool thing about Swagger is it provides an out-of-the-box UI for our docs, and you can easily access it in the URL path declared in the config.</p>
<p>Now let's write some actual documentation!</p>
<p>Hop on to the <code>pets.routes.js</code> file and replace its code with 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> {
  listPets,
  getPet,
  editPet,
  addPet,
  deletePet,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../controllers/pets.controllers.js"</span>;

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

<span class="hljs-comment">/**
 * @swagger
 * components:
 *  schemas:
 *     Pet:
 *      type: object
 *      properties:
 *          id:
 *              type: integer
 *              description: Pet id
 *          name:
 *              type: string
 *              description: Pet name
 *          age:
 *              type: integer
 *              description: Pet age
 *          type:
 *              type: string
 *              description: Pet type
 *          breed:
 *              type: string
 *              description: Pet breed
 *     example:
 *          id: 1
 *          name: Rexaurus
 *          age: 3
 *          breed: labrador
 *          type: dog
 */</span>

<span class="hljs-comment">/**
 * @swagger
 * /pets:
 *  get:
 *     summary: Get all pets
 *     description: Get all pets
 *     responses:
 *      200:
 *         description: Success
 *      500:
 *         description: Internal Server Error
 */</span>
router.get(<span class="hljs-string">"/"</span>, listPets);

<span class="hljs-comment">/**
 * @swagger
 * /pets/{id}:
 *  get:
 *     summary: Get pet detail
 *     description: Get pet detail
 *     parameters:
 *       - in: path
 *         name: id
 *         schema:
 *           type: integer
 *         required: true
 *         description: Pet id
 *     responses:
 *      200:
 *         description: Success
 *      500:
 *         description: Internal Server Error
 */</span>
router.get(<span class="hljs-string">"/:id"</span>, getPet);

<span class="hljs-comment">/**
 * @swagger
 * /pets/{id}:
 *  put:
 *     summary: Edit pet
 *     description: Edit pet
 *     parameters:
 *       - in: path
 *         name: id
 *         schema:
 *           type: integer
 *         required: true
 *         description: Pet id
 *     requestBody:
 *       description: A JSON object containing pet information
 *       content:
 *         application/json:
 *           schema:
 *              $ref: '#/components/schemas/Pet'
 *           example:
 *              name: Rexaurus
 *              age: 12
 *              breed: labrador
 *              type: dog
 *     responses:
 *     200:
 *        description: Success
 *     500:
 *       description: Internal Server Error
 *
 */</span>
router.put(<span class="hljs-string">"/:id"</span>, editPet);

<span class="hljs-comment">/**
 * @swagger
 * /pets:
 *  post:
 *      summary: Add pet
 *      description: Add pet
 *      requestBody:
 *          description: A JSON object containing pet information
 *          content:
 *             application/json:
 *                 schema:
 *                    $ref: '#/components/schemas/Pet'
 *                 example:
 *                    name: Rexaurus
 *                    age: 12
 *                    breed: labrador
 *                    type: dog
 *      responses:
 *      200:
 *          description: Success
 *      500:
 *          description: Internal Server Error
 */</span>
router.post(<span class="hljs-string">"/"</span>, addPet);

<span class="hljs-comment">/**
 * @swagger
 * /pets/{id}:
 *  delete:
 *     summary: Delete pet
 *     description: Delete pet
 *     parameters:
 *       - in: path
 *         name: id
 *         schema:
 *           type: integer
 *         required: true
 *         description: Pet id
 *     responses:
 *     200:
 *        description: Success
 *     500:
 *       description: Internal Server Error
 */</span>
router.delete(<span class="hljs-string">"/:id"</span>, deletePet);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>As you can see, we're adding a special kind of comment for each of our endpoints. This is the way Swagger UI identifies the documentation within our code. We've put them in this file since it makes sense to have the docs as close to the endpoints as possible, but you could place them wherever you want.</p>
<p>If we analyze the comments in detail you could see they're written in a YAML like syntax, and for each of them we specify the endpoint route, HTTP method, a description, the parameters it receives and the possible responses.</p>
<p>All comments are more or less the same except the first one. In that one we're defining a "schema" which is like a typing to a kind of object we can later on reuse in other comments. In our case, we're defining the "Pet" schema which we then use for the <code>put</code> and <code>post</code> endpoints.</p>
<p>If you enter <a target="_blank" href="http://localhost:3000/api-docs/"><code>http://localhost:3000/api-docs/</code></a> again, you should now see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-327.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Documentation UI</em></p>
<p>Each of the endpoints can be expanded, like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-328.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Documentation UI</em></p>
<p>And if we click the "Try it out" button, we can execute an HTTP request and see what the response looks like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-329.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Documentation UI</em></p>
<p>This is really useful for developers in general and people who want to work with our API, and very easy to set up as you can see.</p>
<p>Having an out-of-the-box UI simplifies the interaction with the documentation. And having it within our codebase as well is a great bonus, as we can modify and update it without the need of touching anything else but our own code.</p>
<h1 id="heading-wrapping-up">Wrapping Up</h1>
<p>As always, I hope you enjoyed the handbook and learned something new. If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> or <a target="_blank" href="https://twitter.com/CoccaGerman">Twitter</a>.</p>
<p>See you in the next one!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/5325cccb7a8a7ba25e7780d03c348b2f.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
