<?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[ Idris Olubisi - 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[ Idris Olubisi - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 19 May 2026 04:42:30 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/olanetsoft/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Fix the Python ENOENT Error When Setting Up MCP Servers – A Complete Guide ]]>
                </title>
                <description>
                    <![CDATA[ Getting the "spawn python ENOENT" error while setting up an MCP (Model Context Protocol) server on macOS can be frustrating. But don't worry – in this tutorial, I'll guide you through fixing it by rebuilding your Python virtual environment. By the en... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-fix-the-python-enoent-error-when-setting-up-mcp-servers-a-complete-guide/</link>
                <guid isPermaLink="false">68963890790ac4491c15b00a</guid>
                
                    <category>
                        <![CDATA[ mcp server ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ macOS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Fri, 08 Aug 2025 17:49:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754675334533/6a05e45a-9703-49c0-b427-6c4960c01d86.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Getting the "spawn python ENOENT" error while setting up an MCP (Model Context Protocol) server on macOS can be frustrating. But don't worry – in this tutorial, I'll guide you through fixing it by rebuilding your Python virtual environment.</p>
<p>By the end, you'll have a fully functional MCP server integrated with Claude Desktop in about 10 minutes. This solution applies to any MCP setup facing this standard error after Python upgrades.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-causes-the-enoent-error">What Causes the ENOENT Error?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-diagnose-your-broken-virtual-environment">How to Diagnose Your Broken Virtual Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-completely-rebuild-your-virtual-environment">How to Completely Rebuild Your Virtual Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-mcp-server-dependencies">How to Install MCP Server Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-locate-your-server-files">How to Locate Your Server Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-your-server-setup">How to Test Your Server Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-claude-desktop">How to Configure Claude Desktop</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-restart-claude-desktop-and-test-integration">How to Restart Claude Desktop and Test Integration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-mcp-server-capabilities">Understanding MCP Server Capabilities</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-alternative-installation-methods">Alternative Installation Methods</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-method-1-direct-package-installation">Method 1: Direct Package Installation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-method-2-using-uv-package-manager">Method 2: Using UV Package Manager</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-prevent-future-enoent-errors">How to Prevent Future ENOENT Errors</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-troubleshooting-common-issues">Troubleshooting Common Issues</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-causes-the-enoent-error">What Causes the ENOENT Error?</h2>
<p>The ENOENT (Error NO ENTry) error means your system can’t locate the Python executable at the specified path. This occurs when the file is missing or inaccessible.</p>
<p>On macOS, this typically happens when:</p>
<ul>
<li><p>You've upgraded Python through Homebrew</p>
</li>
<li><p>The <code>brew cleanup</code> command removed old Python versions</p>
</li>
<li><p>Your virtual environment's symlinks now point to non-existent files</p>
</li>
</ul>
<p>What makes this particularly challenging is that your virtual environment folder still exists – it looks fine from the outside, but the Python executable inside is completely broken.</p>
<p>When MCP servers try to spawn Python processes using these broken paths, you get the dreaded ENOENT error. This affects any Python-based MCP server, whether you're building custom tools, connecting to APIs, or working with file systems.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow this tutorial, you'll need:</p>
<ul>
<li><p>macOS with <a target="_blank" href="https://brew.sh/">Homebrew</a> installed</p>
</li>
<li><p>Python 3.10 or higher</p>
</li>
<li><p>An MCP server repository cloned locally</p>
</li>
<li><p><a target="_blank" href="https://claude.ai/download">Claude Desktop</a> installed</p>
</li>
<li><p>Basic familiarity with terminal commands and Python virtual environments</p>
</li>
</ul>
<p>If you haven't cloned an MCP server repository yet, you can start with any open-source MCP server. For this tutorial, I'll use generic examples that work with any MCP setup:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/your-username/your-mcp-server.git
<span class="hljs-built_in">cd</span> your-mcp-server
</code></pre>
<h2 id="heading-how-to-diagnose-your-broken-virtual-environment">How to Diagnose Your Broken Virtual Environment</h2>
<p>First, you need to confirm that your virtual environment is actually the problem. Open your terminal and navigate to your MCP directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /path/to/your/mcp-server
</code></pre>
<p>Now check if your Python executable exists:</p>
<pre><code class="lang-bash">ls -la venv/bin/python*
</code></pre>
<p>If you see broken symlinks or get "No such file or directory" errors, you've found your problem. You might see output like:</p>
<pre><code class="lang-bash">lrwxr-xr-x  1 username  staff  16 Jan  1 12:00 python -&gt; /usr/<span class="hljs-built_in">local</span>/bin/python3.11
lrwxr-xr-x  1 username  staff  16 Jan  1 12:00 python3 -&gt; /usr/<span class="hljs-built_in">local</span>/bin/python3.11
</code></pre>
<p>But when you try to run these Python executables:</p>
<pre><code class="lang-bash">./venv/bin/python --version
</code></pre>
<p>You'll get an error because the target files no longer exist. This confirms your virtual environment is broken and needs rebuilding.</p>
<h2 id="heading-how-to-completely-rebuild-your-virtual-environment">How to Completely Rebuild Your Virtual Environment</h2>
<p>The most reliable solution is to rebuild your virtual environment from scratch. This ensures all paths and dependencies are correctly configured for your current Python installation.</p>
<p>Here's your step-by-step rebuild process:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Make sure you're in the MCP server directory</span>
<span class="hljs-built_in">cd</span> /path/to/your/mcp-server

<span class="hljs-comment"># Remove the corrupted virtual environment</span>
rm -rf venv

<span class="hljs-comment"># Create a fresh virtual environment</span>
python3 -m venv venv

<span class="hljs-comment"># Activate the new environment</span>
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<p>You should now see <code>(venv)</code> in your terminal prompt, indicating the virtual environment is active. This prefix confirms you're working within the isolated Python environment.</p>
<h2 id="heading-how-to-install-mcp-server-dependencies">How to Install MCP Server Dependencies</h2>
<p>With your fresh virtual environment active, install the MCP server and its dependencies. The exact installation command depends on your specific MCP server, but typically follows one of these patterns:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># For package-based installation</span>
pip install -e .

<span class="hljs-comment"># Or for requirements file</span>
pip install -r requirements.txt

<span class="hljs-comment"># Or for specific MCP frameworks</span>
pip install fastmcp
</code></pre>
<p>Common MCP server dependencies include:</p>
<ul>
<li><p>FastMCP for the server framework</p>
</li>
<li><p>JSON-RPC libraries for communication protocols</p>
</li>
<li><p>HTTP clients for API integrations</p>
</li>
<li><p>File system utilities for local operations</p>
</li>
</ul>
<p>The installation process displays all packages as they install. Don't worry if you see deprecation warnings – they're normal and won't affect functionality.</p>
<h2 id="heading-how-to-locate-your-server-files">How to Locate Your Server Files</h2>
<p>After installation, identify where your main server file lives. Run this command to find all server.py files:</p>
<pre><code class="lang-bash">find . -name <span class="hljs-string">"server.py"</span> -<span class="hljs-built_in">type</span> f
</code></pre>
<p>You may see results like:</p>
<ul>
<li><p><code>./server.py</code> (in the root directory)</p>
</li>
<li><p><code>./src/server.py</code> (in a source directory)</p>
</li>
<li><p><code>./mcp_server/server.py</code> (in a package directory)</p>
</li>
</ul>
<p>Check your current directory structure:</p>
<pre><code class="lang-bash">ls -la
</code></pre>
<p>Look for the main server entry point. Most MCP servers follow standard Python project structures with either a root-level server file or one nested in a package directory.</p>
<h2 id="heading-how-to-test-your-server-setup">How to Test Your Server Setup</h2>
<p>Now you’ll want to test your server to ensure it's working correctly. Start with the main server file you identified:</p>
<pre><code class="lang-bash">python server.py
</code></pre>
<p>If this is the correct server and everything is configured correctly, you'll see output similar to:</p>
<pre><code class="lang-typescript">╭─ MCP Server ───────────────────────────────────────────────────────────────╮
│ 🖥️  Server name: Example-MCP                                              │
│ 📦 Transport: STDIO                                                        │
│ 🤝 Protocol: <span class="hljs-built_in">JSON</span>-RPC                                                      │
╰────────────────────────────────────────────────────────────────────────────╯
[INFO] Starting MCP server <span class="hljs-keyword">with</span> transport <span class="hljs-string">'stdio'</span>
[INFO] Server ready <span class="hljs-keyword">for</span> connections
</code></pre>
<p>This output confirms your MCP server is working correctly. The server uses standard input/output (STDIO) for communication, which is perfect for Claude Desktop integration. You can stop the server with <code>Ctrl+C</code>.</p>
<h2 id="heading-how-to-configure-claude-desktop">How to Configure Claude Desktop</h2>
<p>Now that your server runs properly, configure Claude Desktop to connect to it. The configuration file location depends on your operating system:</p>
<p><strong>For macOS:</strong></p>
<pre><code class="lang-bash">~/Library/Application Support/Claude/claude_desktop_config.json
</code></pre>
<p><strong>For Windows:</strong></p>
<pre><code class="lang-bash">%APPDATA%\Claude\claude_desktop_config.json
</code></pre>
<p><strong>For Linux:</strong></p>
<pre><code class="lang-bash">~/.config/Claude/claude_desktop_config.json
</code></pre>
<p>Create or edit this file with your exact paths. Your configuration should look like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"mcpServers"</span>: {
    <span class="hljs-attr">"example-mcp"</span>: {
      <span class="hljs-attr">"command"</span>: <span class="hljs-string">"/Users/yourusername/path/to/mcp-server/venv/bin/python"</span>,
      <span class="hljs-attr">"args"</span>: [<span class="hljs-string">"/Users/yourusername/path/to/mcp-server/server.py"</span>],
      <span class="hljs-attr">"cwd"</span>: <span class="hljs-string">"/Users/yourusername/path/to/mcp-server"</span>
    }
  }
}
</code></pre>
<p>Replace <code>/Users/yourusername/path/to/mcp-server/</code> with your actual path. You can get your precise path by running <code>pwd</code> in your MCP server directory.</p>
<p>The configuration tells Claude Desktop:</p>
<ul>
<li><p>Which Python interpreter to use (from your virtual environment)</p>
</li>
<li><p>Where to find the server script</p>
</li>
<li><p>Which directory to run the server from</p>
</li>
</ul>
<h2 id="heading-how-to-restart-claude-desktop-and-test-integration">How to Restart Claude Desktop and Test Integration</h2>
<p>After saving your configuration file, altogether quit Claude Desktop (not just close the window). On macOS, use <code>Cmd+Q</code> or right-click the dock icon and select Quit. Then restart Claude Desktop.</p>
<p>Once Claude Desktop is running again, test your MCP integration. You can verify the connection by:</p>
<ol>
<li><p>Looking for your MCP server name in Claude's interface</p>
</li>
<li><p>Testing basic MCP functionality with prompts like:</p>
<ul>
<li><p>"What MCP tools are available?"</p>
</li>
<li><p>"Can you check the MCP server status?"</p>
</li>
<li><p>"Show me the available MCP commands"</p>
</li>
</ul>
</li>
</ol>
<p>If everything is working correctly, Claude will respond using the MCP server tools, confirming successful integration.</p>
<h2 id="heading-understanding-mcp-server-capabilities">Understanding MCP Server Capabilities</h2>
<p>MCP servers extend Claude's capabilities by providing structured access to external tools and data sources. Common MCP server implementations include:</p>
<ol>
<li><p>File system operations: MCP servers can provide controlled access to local files, allowing Claude to read, analyze, and process documents while maintaining security boundaries.</p>
</li>
<li><p>API integrations: Connect Claude to external services through MCP servers that handle authentication, rate limiting, and data formatting for various APIs.</p>
</li>
<li><p>Database connections: Query databases safely through MCP servers that manage connections, handle credentials securely, and format results for Claude's consumption.</p>
</li>
<li><p>Custom tools: Build specialized tools for your workflow, from code analysis to data processing, all accessible through the standardized MCP interface.</p>
</li>
</ol>
<p>The beauty of MCP is its flexibility – you can create servers for virtually any tool or service you need Claude to interact with.</p>
<h2 id="heading-alternative-installation-methods">Alternative Installation Methods</h2>
<p>If you want more streamlined approaches for future setups, here are two excellent alternatives:</p>
<h3 id="heading-method-1-direct-package-installation">Method 1: Direct Package Installation</h3>
<p>For MCP servers available as packages, you can install directly:</p>
<pre><code class="lang-bash">pip install mcp-server-package
</code></pre>
<p>Then use this simpler configuration:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"mcpServers"</span>: {
    <span class="hljs-attr">"example-mcp"</span>: {
      <span class="hljs-attr">"command"</span>: <span class="hljs-string">"mcp-server-command"</span>
    }
  }
}
</code></pre>
<p>This method works when the MCP server provides a command-line entry point through its setup configuration.</p>
<h3 id="heading-method-2-using-uv-package-manager">Method 2: Using UV Package Manager</h3>
<p>UV provides more robust dependency management – perfect if you're tired of Python version conflicts:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install UV</span>
curl -LsSf https://astral.sh/uv/install.sh | sh

<span class="hljs-comment"># Use UV in your configuration</span>
{
  <span class="hljs-string">"mcpServers"</span>: {
    <span class="hljs-string">"example-mcp"</span>: {
      <span class="hljs-string">"command"</span>: <span class="hljs-string">"uv"</span>,
      <span class="hljs-string">"args"</span>: [
        <span class="hljs-string">"run"</span>,
        <span class="hljs-string">"--with"</span>, <span class="hljs-string">"fastmcp"</span>,
        <span class="hljs-string">"python"</span>,
        <span class="hljs-string">"/path/to/mcp-server/server.py"</span>
      ],
      <span class="hljs-string">"cwd"</span>: <span class="hljs-string">"/path/to/mcp-server"</span>
    }
  }
}
</code></pre>
<p>UV automatically manages Python versions and dependencies, reducing the likelihood of environment-related errors.</p>
<h2 id="heading-how-to-prevent-future-enoent-errors">How to Prevent Future ENOENT Errors</h2>
<p>To avoid this issue in the future, follow these best practices:</p>
<h3 id="heading-1-use-virtual-environment-copies-instead-of-symlinks">1. Use Virtual Environment Copies Instead of Symlinks</h3>
<p>When creating virtual environments, use the <code>--copies</code> flag:</p>
<pre><code class="lang-bash">python3 -m venv venv --copies
</code></pre>
<p>This creates actual copies of files instead of symlinks, making your environment more resilient to Python upgrades.</p>
<h3 id="heading-2-pin-your-homebrew-python-version">2. Pin Your Homebrew Python Version</h3>
<p>Prevent automatic Python upgrades that break environments:</p>
<pre><code class="lang-bash">brew pin python@3.11
</code></pre>
<p>Remember to unpin when you're ready to upgrade intentionally.</p>
<h3 id="heading-3-create-a-health-check-script">3. Create a Health Check Script</h3>
<p>Save this script as <code>health_check.sh</code> in your MCP server directory:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># health_check.sh</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Checking Python virtual environment..."</span>
<span class="hljs-built_in">source</span> venv/bin/activate

python -c <span class="hljs-string">"import sys; print(f'Python: {sys.executable}')"</span>
python -c <span class="hljs-string">"print('✓ Python is working')"</span>

<span class="hljs-comment"># Check for common MCP dependencies</span>
python -c <span class="hljs-string">"import json; print('✓ JSON module available')"</span>
python -c <span class="hljs-string">"import asyncio; print('✓ Asyncio available')"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Health check complete!"</span>
</code></pre>
<p>Make it executable and run it periodically:</p>
<pre><code class="lang-bash">chmod +x health_check.sh
./health_check.sh
</code></pre>
<h3 id="heading-4-document-your-python-version">4. Document Your Python Version</h3>
<p>Create a <code>.python-version</code> file in your project:</p>
<pre><code class="lang-bash">python --version &gt; .python-version
</code></pre>
<p>This helps you remember which Python version the project was built with.</p>
<h2 id="heading-troubleshooting-common-issues">Troubleshooting Common Issues</h2>
<p>Even with the fix applied, you might encounter these challenges:</p>
<h3 id="heading-import-errors">Import Errors</h3>
<p>If you see import-related errors, ensure all dependencies are installed:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> venv/bin/activate
pip list  <span class="hljs-comment"># Check installed packages</span>
pip install -r requirements.txt  <span class="hljs-comment"># Reinstall if needed</span>
</code></pre>
<h3 id="heading-permission-denied-errors">Permission Denied Errors</h3>
<p>Make sure your server file is executable:</p>
<pre><code class="lang-bash">chmod +x server.py
</code></pre>
<h3 id="heading-claude-desktop-not-finding-the-server">Claude Desktop Not Finding the Server</h3>
<p>Double-check your configuration paths are absolute, not relative:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Good - absolute path</span>
<span class="hljs-string">"/Users/username/projects/mcp-server/server.py"</span>

<span class="hljs-comment"># Bad - relative path</span>
<span class="hljs-string">"./server.py"</span>
</code></pre>
<h3 id="heading-server-starts-but-claude-cant-connect">Server Starts, But Claude Can't Connect</h3>
<p>Verify that the transport method matches between your server and the configuration. Most MCP servers use STDIO, but some might use HTTP or WebSocket transports.</p>
<h3 id="heading-multiple-python-installations">Multiple Python Installations</h3>
<p>If you have multiple Python versions, be explicit about which one to use:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Check available Python versions</span>
ls -la /usr/<span class="hljs-built_in">local</span>/bin/python*

<span class="hljs-comment"># Use a specific version</span>
/usr/<span class="hljs-built_in">local</span>/bin/python3.11 -m venv venv
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've successfully fixed the "spawn python ENOENT" error by rebuilding your Python virtual environment and properly configuring your MCP server for Claude Desktop. You've also learned how to prevent future mistakes and troubleshoot common issues.</p>
<p>With your MCP server running smoothly, you can now:</p>
<ul>
<li><p>Build custom tools that extend Claude's capabilities</p>
</li>
<li><p>Create integrations with your favorite services</p>
</li>
<li><p>Develop specialized workflows for your specific needs</p>
</li>
<li><p>Share your MCP servers with the community</p>
</li>
</ul>
<p>The <a target="_blank" href="https://www.anthropic.com/news/model-context-protocol">MCP</a> ecosystem is growing rapidly, with new servers and tools being developed constantly. Whether you're building file system tools, API integrations, or custom utilities, you now have the foundation to create and maintain robust MCP servers.</p>
<p>Happy building, and enjoy your error-free development journey! For more tutorials, follow my work on <a target="_blank" href="https://github.com/Olanetsoft">GitHub</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Paraphrasing Tool with ReactJs & ChatGPT Turbo ]]>
                </title>
                <description>
                    <![CDATA[ In a world where online content is growing exponentially, it's more important than ever to produce unique content that stands out. Paraphrasing tools can offer a quick solution to help you develop unique ideas and create original content.  With the h... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-paraphrasing-tool-with-reactjs-chatgpt-turbo/</link>
                <guid isPermaLink="false">66b905ca626438a622a1ef82</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Fri, 31 Mar 2023 17:51:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/paraphrase.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In a world where online content is growing exponentially, it's more important than ever to produce unique content that stands out.</p>
<p>Paraphrasing tools can offer a quick solution to help you develop unique ideas and create original content. </p>
<p>With the help of ReactJs and ChatGPT Turbo, developers can build a powerful and efficient paraphrasing tool that delivers accurate and effective results.</p>
<p>With AI, you can automate repetitive tasks, test code more efficiently, and improve the overall quality of your software. Recently, we have seen a ton of developers asking questions like "How do I create a chatbot in Reactjs?", "How do I use ChatGPT API in React?", and "Can ChatGPT write JavaScript code?"</p>
<p>This article will teach us how to build a paraphrasing tool using ReactJs, ChatGPT Turbo, and TailwidCSS for styling.</p>
<h2 id="heading-introduction-to-chatgpt-turbo">Introduction to ChatGPT Turbo</h2>
<p><a target="_blank" href="https://openai.com/blog/introducing-chatgpt-and-whisper-apis">ChatGPT Turbo</a> is a recently introduced feature by <a target="_blank" href="https://openai.com/">OpenAI</a> for ChatGPT Plus subscribers, which aims to provide superior responses at an accelerated pace.</p>
<p>Turbo mode is presently in its alpha phase, but we will use the <code>gpt-3.5-turbo</code> mode in this tutorial. Turbo mode is designed to deliver high-quality responses. It is an advanced version of ChatGPT's Default mode, requiring minimal computational resources for real-time applications.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Make sure to have Node.js and npm installed on your computer. If you don't, you can go <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"><strong>here</strong></a>.</li>
</ul>
<p>You can verify that you have Node.js installed by using the following terminal command:</p>
<pre><code class="lang-bash">        node -v &amp;&amp; npm -v
</code></pre>
<ul>
<li><p>Install and configure Git on your PC. If you haven't, go <a target="_blank" href="https://git-scm.com/">here</a> to install it.</p>
</li>
<li><p>You should have a basic understanding of JavaScript/TypeScript</p>
</li>
</ul>
<h2 id="heading-project-setup-and-installation">Project Setup and Installation</h2>
<p>To quickly get started with the project setup and installation, clone this <a target="_blank" href="https://github.com/Olanetsoft/ai-paraphrasing-tool-with-nextjs/tree/starter"><strong>project on GitHub</strong></a>. Make sure you're on the <code>starter</code> branch using the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/Olanetsoft/ai-paraphrasing-tool-with-nextjs.git
</code></pre>
<p>Next, launch the project locally after cloning it using the following command in your terminal.</p>
<p>Here's how you can install the project using <code>npm</code>:</p>
<pre><code class="lang-solidity">cd ai<span class="hljs-operator">-</span>paraphrasing<span class="hljs-operator">-</span>tool<span class="hljs-operator">-</span>with<span class="hljs-operator">-</span>nextjs <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> npm i <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> npm start
</code></pre>
<h2 id="heading-how-to-design-the-layout-for-the-paraphrasing-tool">How to Design the Layout for the Paraphrasing Tool</h2>
<p>In the previous step, you cloned and installed the starter project we will be using in this article. It contains the default layout for the project we will build in this tutorial.</p>
<p>Navigate to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> in the browser. Here is what you should have after cloning and installing the project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679840553951/b45632bc-0bd5-4e6c-a59b-229a88e5da9d.png" alt="Paraphrasing Tool with ReactJs &amp; ChatGPT Turbo" width="1692" height="1246" loading="lazy"></p>
<p>Navigate to the project directory and rename the <code>.env.example</code> to <code>env</code>. Or you can create a new <code>.env</code> file with the following command in the root directory of the project.</p>
<pre><code class="lang-bash">touch .env
</code></pre>
<p>Update the <code>.env</code> with the following:</p>
<pre><code class="lang-bash">NEXT_PUBLIC_ENV_VARIABLE_OPEN_AI_API_KEY=&lt;Your-API-Key&gt;
</code></pre>
<p>Replace <code>&lt;Your-API-Key&gt;</code> with your <code>API</code> key from OpenAI. Visit the <a target="_blank" href="https://platform.openai.com/">OpenAI website</a>, create an account for free, and generate an API key.</p>
<p>You should have something similar to what is shown below to implement the paraphrasing functionality in your application with ChapGPT Turbo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679841350457/3e0ee4ad-64d7-4503-84a9-6a90fe9c02c3.png" alt="Paraphrasing Tool with ReactJs &amp; ChatGPT Turbo Project  Directory" width="249" height="555" loading="lazy"></p>
<h2 id="heading-how-to-integrate-chatgpt-turbo">How to Integrate ChatGPT Turbo</h2>
<p>In this section, you will integrate ChatGPT Turbo and implement the paraphrasing functionality. </p>
<p>To start with, let's navigate to the <code>paraphrase.ts</code> file under the <code>api</code> directory and add the following snippet:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Import necessary types from Next.js</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;

<span class="hljs-comment">// Check if required environment variable is set</span>
<span class="hljs-keyword">if</span> (!process.env.NEXT_PUBLIC_ENV_VARIABLE_OPEN_AI_API_KEY) {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Missing env var from OpenAI"</span>);
}

<span class="hljs-comment">// Define ChatGPTAgent type as a union of user and system</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> ChatGPTAgent = <span class="hljs-string">"user"</span> | <span class="hljs-string">"system"</span>;

<span class="hljs-comment">// Define ChatGPTMessage interface</span>
<span class="hljs-keyword">interface</span> ChatGPTMessage {
  role: ChatGPTAgent;
  content: <span class="hljs-built_in">string</span>;
}

<span class="hljs-comment">// Define promptPayload interface</span>
<span class="hljs-keyword">interface</span> promptPayload {
  model: <span class="hljs-built_in">string</span>;
  messages: ChatGPTMessage[];
  temperature: <span class="hljs-built_in">number</span>;
  max_tokens: <span class="hljs-built_in">number</span>;
}

<span class="hljs-comment">// Define async handler function</span>
<span class="hljs-keyword">const</span> handler = <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Get prompt from request body</span>
    <span class="hljs-keyword">const</span> prompt = req.body.prompt;

    <span class="hljs-comment">// Validate the prompt</span>
    <span class="hljs-keyword">if</span> (!prompt) {
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-string">"No prompt in the request"</span>, { status: <span class="hljs-number">400</span> });
    }

    <span class="hljs-comment">// Define payload object to send to OpenAI API</span>
    <span class="hljs-keyword">const</span> payload: promptPayload = {
      model: <span class="hljs-string">"gpt-3.5-turbo"</span>,
      messages: [{ role: <span class="hljs-string">"user"</span>, content: prompt }],
      temperature: <span class="hljs-number">1</span>,
      max_tokens: <span class="hljs-number">500</span>,
    };

    <span class="hljs-comment">// Send request to OpenAI API and wait for response</span>
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.openai.com/v1/chat/completions"</span>, {
      headers: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
        Authorization: <span class="hljs-string">`Bearer <span class="hljs-subst">${
          process.env.NEXT_PUBLIC_ENV_VARIABLE_OPEN_AI_API_KEY ?? <span class="hljs-string">""</span>
        }</span>`</span>,
      },
      method: <span class="hljs-string">"POST"</span>,
      body: <span class="hljs-built_in">JSON</span>.stringify(payload),
    });

    <span class="hljs-comment">// Parse response JSON and send it back in the response</span>
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
    <span class="hljs-keyword">return</span> res.json(data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Log any errors that occur during the request</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"The Error: "</span>, error);
  }
};

<span class="hljs-comment">// Export the handler function as the default export</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler;
</code></pre>
<p>Let's go through what's going on in the code snippet above:</p>
<ul>
<li><p>Import the <code>NextApiRequest</code> and <code>NextApiResponse</code> types from Next.js.</p>
</li>
<li><p>Check if <code>NEXT_PUBLIC_ENV_VARIABLE_OPEN_AI_API_KEY</code>, an environment variable, is set and throw an error if it's not.</p>
</li>
<li><p>Define a type and two interfaces for ChatGPT agents and messages – <code>ChatGPTAgent</code> and <code>ChatGPTMessage</code>, respectively.</p>
</li>
<li><p>Define an interface for the request payload to OpenAI API and an async handler function that takes a Next.js request and response as arguments.</p>
</li>
<li><p>Get a prompt from the request body and validate it.</p>
</li>
<li><p>Send a request to <code>OpenAI API</code> with the prompt and other parameters in the request payload.</p>
</li>
<li><p>Parse and return the JSON response from the OpenAI API.</p>
</li>
</ul>
<p>Next, we will consume the new endpoint we just implemented. Navigate to the <code>index.vue</code> file in the pages directory, and update it with the following code snippet:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//...</span>

<span class="hljs-comment">// Define a default function component called Home</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-comment">// Define three state variables for the original text, paraphrased text, and paraphrase mode</span>
  <span class="hljs-keyword">const</span> [originalText, setOriginalText] = useState&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [paraphrasedText, setParaphrasedText] = useState&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [paraphraseMode, setParaphraseMode] = useState&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">"Standard"</span>);

  <span class="hljs-comment">// Define a ref for the text area element</span>
  <span class="hljs-keyword">const</span> textAreaRef = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-comment">// Define a state variable for the loading state of the paraphrasing operation</span>
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">false</span>);

  <span class="hljs-comment">// Construct a prompt string based on the original text and paraphrase mode</span>
  <span class="hljs-keyword">const</span> prompt = <span class="hljs-string">`Paraphrase "<span class="hljs-subst">${originalText}</span>" using <span class="hljs-subst">${paraphraseMode}</span> mode. Do not add any additional word.`</span>;

  <span class="hljs-comment">// Define an async function to handle the paraphrasing operation</span>
  <span class="hljs-keyword">const</span> handleParaphrase = <span class="hljs-keyword">async</span> (e: React.FormEvent) =&gt; {
    <span class="hljs-comment">// Prevent form submission if original text is empty</span>
    <span class="hljs-keyword">if</span> (!originalText) {
      toast.error(<span class="hljs-string">"Enter text to paraphrase!"</span>);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Set the loading state and reset the paraphrased text</span>
    setLoading(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">// Send a POST request to the "/api/paraphrase" API endpoint with the prompt in the request body</span>
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/paraphrase"</span>, {
      method: <span class="hljs-string">"POST"</span>,
      headers: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      body: <span class="hljs-built_in">JSON</span>.stringify({
        prompt,
      }),
    });

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

    <span class="hljs-comment">// Set the paraphrased text to the first choice's message content in the response</span>
    setParaphrasedText(data.choices[<span class="hljs-number">0</span>].message.content);

    <span class="hljs-comment">// Reset the loading state</span>
    setLoading(<span class="hljs-literal">false</span>);
  };

  <span class="hljs-comment">// Return the JSX for the Home component</span>
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
    {<span class="hljs-comment">/* //... */</span>}
    &lt;/&gt;
  );
}
</code></pre>
<p>In the code snippet above:</p>
<ul>
<li><p>Initialize three state variables using the <code>useState</code> hook: <code>originalText</code>, <code>paraphrasedText</code>, and <code>paraphraseMode</code>.</p>
</li>
<li><p>Initialize a reference to a <code>textarea</code> element using the <code>useRef</code> hook and a loading state variable.</p>
</li>
<li><p>Define <code>handleParaphrase</code>, a function that sends a <code>POST</code> request to <code>/api/paraphrase</code> with a prompt to paraphrase the text in the originalText state variable using the selected <code>paraphraseMode</code>.</p>
</li>
</ul>
<p>The component returns a UI with a <code>textarea</code> element for inputting text to paraphrase, a <code>select</code> element for choosing the paraphrase mode, a <code>button</code> for initiating the paraphrasing process, and a <code>div</code> element for displaying the paraphrased text.</p>
<p>Update the <code>Paraphrase</code> button with the following code snippet to add the <code>onClick</code> event:</p>
<pre><code class="lang-typescript">  &lt;button
     onClick={handleParaphrase}
     <span class="hljs-comment">//...</span>
     &gt;
       Paraphrase
 &lt;/button&gt;
</code></pre>
<p>Let's test our application. You should have something similar to what you see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/praraphrase.gif" alt="praraphrase" width="600" height="400" loading="lazy"></p>
<p>You can find the complete code in this GitHub repository <a target="_blank" href="https://github.com/Olanetsoft/ai-paraphrasing-tool-with-nextjs"><strong>here</strong></a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article provides a step-by-step guide on how to build a paraphrasing tool using ReactJs, ChatGPT Turbo, and TailwindCSS for styling the application.</p>
<p>I'd love to connect with you via <a target="_blank" href="https://twitter.com/olanetsoft"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/olubisi-idris-ayinde-05727b17a/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/Olanetsoft"><strong>GitHub</strong></a> | <a target="_blank" href="https://idrisolubisi.com/"><strong>Portfolio</strong></a></p>
<p>See you in my next blog article. Take care!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Decentralized Identity – Build a Profile with Next.js, Ethereum & Ceramic Network ]]>
                </title>
                <description>
                    <![CDATA[ Long-standing centralized intermediaries, like the government or big companies, are the ones who make and keep your ID information in traditional systems that manage who you are.  But this implies that you have no control over the information relatin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/decentralized-identity-build-a-profile-with-ethereum-ceramic-and-reactjs/</link>
                <guid isPermaLink="false">66b905ce5730a049b6bfea7d</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ethereum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Fri, 17 Feb 2023 22:44:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/Decentralized-Identity--Build-a-Profile-with-NextJs--Ethereum---Ceramic-Network.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Long-standing centralized intermediaries, like the government or big companies, are the ones who make and keep your ID information in traditional systems that manage who you are. </p>
<p>But this implies that you have no control over the information relating to your identification, who has access to <a target="_blank" href="https://www.dol.gov/general/ppii#:~:text=Personal%20Identifiable%20Information%20(PII)%20is,either%20direct%20or%20indirect%20means.">personally identifiable information (PII)</a>, and to what extent.</p>
<p>As a result, Decentralized Identity provides identity-related information that is self-controlled, private, and portable. Decentralized identifiers and attestations serve as the main building pieces. </p>
<p>Thanks to Ceramic's decentralized application databases, application developers can reuse data across applications and automatically make them interoperable.</p>
<p>In this article, you will learn about Decentralized Identity, Decentralized Identifiers, Ceramic network, and how to build a decentralized identity profile with Ethereum on Ceramic Networks.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li>What is a Decentralized Identity?</li>
<li>What are Decentralized Identifiers?</li>
<li>What is Ceramic Data Network?</li>
<li>Why Ceramic Network?</li>
<li>How to Build a Decentralized Identity Profile with Next.js</li>
<li>Prerequisites</li>
<li>Project Setup and Installation</li>
<li>Install TailwindCSS in Next.js</li>
<li>Authenticate Users</li>
<li>Create/Update User Profile</li>
<li>How to Test the Application</li>
<li>Conclusion</li>
<li>References</li>
</ul>
<h2 id="heading-what-is-a-decentralized-identity">What is a Decentralized Identity?</h2>
<p><a target="_blank" href="https://ethereum.org/en/decentralized-identity/">Decentralized Identity</a> is a digital identification concept where people, companies, and items are in charge of their data and can share it selectively without relying on a centralized authority. </p>
<p>This is made possible by using decentralized technologies, such as blockchain. These give people control and ownership over the information associated with their identities rather than having it stored on a central server or managed by a third party.</p>
<p>A decentralized identity is a self-owned, independent identity that enables trusted data exchange.</p>
<p>Blockchain-based digital wallets, such as those used to store and handle cryptocurrencies, serve as a practical illustration of decentralized identification. Users of these wallets control the private keys that provide them access to their money and can distribute their public keys to others to accept payments from them.</p>
<p>Users who manage their private keys can conduct transactions with others without relying on a central authority, such as a bank, and keep custody of their money.</p>
<h2 id="heading-what-are-decentralized-identifiers">What are Decentralized Identifiers?</h2>
<p>Decentralized identifiers (DIDs) are issued, held, and controlled by individuals. Since they are kept on peer-to-peer networks or distributed ledgers (blockchains), they are globally unique, highly available, and cryptographically verifiable. </p>
<p>Decentralized identifiers can be associated with individuals, groups, or governmental entities.</p>
<p>DIDs are a vital component of the developing decentralized identity ecosystem. They are designed to offer a uniform process for developing, maintaining, and exchanging digital identities unaffiliated with any one company or piece of technology. </p>
<p>This implies that a DID can be maintained and controlled by the person or entity to which it belongs and utilized across various systems and applications.</p>
<p>In recent years, smart contract platforms like Ethereum have demonstrated the utility of decentralized applications (dApps) that can be assembled like blocks to create new applications. This is especially evident in tokens that build upon one another, in DeFi protocols that use one another, and so on.</p>
<p>Thanks to Ceramic, data on the internet can now have the same kind of composability. Any data type, including profiles, social connections, blog posts, identities, reputations, and so on., can be included. You will learn more about Ceramic Network in the section below.</p>
<h2 id="heading-what-is-ceramic-network">What is Ceramic Network?</h2>
<p><a target="_blank" href="https://ceramic.network/">Ceramic</a> is a public, permissionless, open-source protocol that offers computation, state transitions, and consensus for all data structures on the decentralized web. </p>
<p>With the help of stream processing provided by Ceramic, developers can build apps that are strong, safe, trustless, and censorship-resistant using dynamic information – without using unreliable database servers.</p>
<p>Ceramic stores all content in smart documents, which are append-only IPFS logs. Before being anchored in a blockchain for consensus, each commit is verified by a decentralized identification (DID).</p>
<p>All papers in Ceramic are openly discoverable and can be referenced by other documents or queried by any other network user because the system is entirely peer-to-peer.</p>
<h2 id="heading-why-ceramic-network">Why Ceramic Network?</h2>
<p>Data interoperability is one of Ceramic Network's key benefits. This platform features a flexible and modular data schema that enables the decentralized and interoperable sharing and combining of various sorts of data. </p>
<p>Developers now have an easier time creating decentralized identification solutions that can be integrated with other programs and systems.</p>
<p>The infrastructure of Ceramic Network is scalable, fault-tolerant, decentralized, and highly available. This enables developers to create robust decentralized identity systems available to users everywhere.</p>
<p>Ceramic Network also provides a set of developer tools and libraries, making it simple to create decentralized identity apps and services. These tools include SDKs, APIs, developer guides, and an expanding ecosystem of open-source tools and libraries.</p>
<p>Now that you have learnt the theories behind decentralized identity, let's take a practical deep dive and get your hands dirty.</p>
<h2 id="heading-how-to-build-a-decentralized-identity-profile-with-nextjs">How to Build a Decentralized Identity Profile with Next.js</h2>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To go through this tutorial, you'll need some experience with JavaScript and React.js. Experience with Next.js isn't a requirement, but it's nice to have.</p>
<p>Make sure to have Node.js or npm installed on your computer. If you don't, click <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"><strong>here</strong></a>.</p>
<p>Also, it'll be very useful to have a basic understanding of blockchain technology and Web3 concepts.</p>
<h3 id="heading-project-setup-and-installation">Project Setup and Installation</h3>
<p>Navigate to the terminal and <code>cd</code> into any directory of your choice. Then run the following commands:</p>
<pre><code class="lang-bash">mkdir decentralized-identity-project
<span class="hljs-built_in">cd</span> decentralized-identity-project
npx create-next-app@latest .
</code></pre>
<p>Accept the following options:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676416198416/0b46fd0f-d47a-4533-9450-a79007205efe.png" alt="Image" width="611" height="71" loading="lazy"></p>
<p>Install the <code>@self.id/react</code> and <code>@self.id/web</code> packages using the code snippet below:</p>
<pre><code class="lang-bash">npm install @self.id/web @self.id/react
</code></pre>
<p>Next, start the app using the following command:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>You should have something similar to what is shown below: the default boilerplate layout for Next.js 13.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676416289117/799cfc73-78b3-49f9-8b72-a407813f7d9c.png" alt="Image" width="1292" height="884" loading="lazy"></p>
<h3 id="heading-install-tailwindcss-in-nextjs">Install TailwindCSS in Next.js</h3>
<p>In this section, you will set up Tailwind CSS in a Next.js project. Install <code>tailwindcss</code> and its peer dependencies via npm, and then run the init command to generate both <code>tailwind.config.js</code> and <code>postcss.config.js</code>.</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>Navigate to the <code>tailwind.config.js</code> file, and add the paths to your template files with the following code snippet.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx}"</span>,

    <span class="hljs-comment">// Or if using `src` directory:</span>
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Delete all the CSS styles inside <code>globals.css</code> . Add the <code>@tailwind</code> directives for each of Tailwind’s layers to your <code>globals.css</code> file.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<h3 id="heading-configure-the-provider-component">Configure the Provider Component</h3>
<p>The <code>Provider</code> component must be placed at the top of the application tree to use the hooks detailed below. You can use it to supply an initial state as well as a specific configuration for the <a target="_blank" href="http://Self.ID">Self.ID</a> clients and queries.</p>
<p>Update the <code>_app.js</code> file under the pages folder with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Provider component from the "@self.id/react" library.</span>
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/react"</span>;

<span class="hljs-comment">// Import the "globals.css" file from the "@/styles" directory.</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@/styles/globals.css"</span>;

<span class="hljs-comment">// Define the App component as a default export.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{

  <span class="hljs-comment">// Render the Provider component, which provides authentication and authorization functionality to the application.</span>
  <span class="hljs-comment">// Pass a client prop to the Provider component, which configures the Ceramic testnet with the "testnet-clay" value.</span>
  <span class="hljs-comment">// Render the Component with its props inside the Provider component, which allows the application to access the authentication and authorization context.</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">ceramic:</span> "<span class="hljs-attr">testnet-clay</span>" }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Provider</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code snippet above, we:</p>
<ul>
<li>Imported a context provider component and global CSS styles and then defined an <code>App</code> component that wraps the entire application with the context provider.</li>
<li>Configured the context provider with a Ceramic testnet client, which allows the application to access authentication and authorization functionality.</li>
<li>Finally, the <code>Component</code> is rendered with its props inside the context provider, allowing the application to access the authentication and authorization context.</li>
</ul>
<h3 id="heading-build-the-layout">Build the Layout</h3>
<p>Next, navigate to the <code>index.js</code> file under the <code>pages</code> folder and update it with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Import the Head component from the "next/head" module.</span>
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

<span class="hljs-comment">// Import the useViewerConnection and useViewerRecord hooks from the "@self.id/react" library.</span>
<span class="hljs-keyword">import</span> { useViewerConnection, useViewerRecord } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/react"</span>;

<span class="hljs-comment">// Import the EthereumAuthProvider component from the "@self.id/web" library.</span>
<span class="hljs-keyword">import</span> { EthereumAuthProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@self.id/web"</span>;

<span class="hljs-comment">// Import the useState hook from the "react" module.</span>
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;


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

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>
          Decentralized Identity: Build a Profile with NextJs, Ethereum &amp; Ceramic Network
        <span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen bg-gray-200"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gray-600 py-4 px-4 sm:px-6 lg:px-8 lg:py-6 shadow-lg text-white"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto px-6 md:px-0"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-white text-center"</span>&gt;</span>
              Decentralized Identity: Build a Profile with NextJs, Ethereum &amp; Ceramic Network
            <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center pt-20 font-sans overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-md w-full mx-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-10 rounded-lg shadow-lg"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>
                  &gt;</span>
                    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">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your name"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"bio"</span>
                  &gt;</span>
                    Bio
                  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"bio"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"bio"</span>
                    <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Write something about yourself"</span>
                  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
                    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"username"</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">className</span>=<span class="hljs-string">"border border-gray-300 p-2 w-full rounded-lg"</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">id</span>=<span class="hljs-string">"username"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your username"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
                  &gt;</span>
                    Update Profile
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                  &gt;</span>
                    Connect Wallet
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>To start the application, run the following command and navigate to localhost:3000 on your browser; you should have something similar to what is shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676418666618/bc0620d9-d7bb-4297-bdb1-6021d08d8d6c.png" alt="Image" width="1544" height="1060" loading="lazy"></p>
<h3 id="heading-how-to-authenticate-users">How to Authenticate Users</h3>
<p>In this section, you will implement user authentication to allow users to connect their wallets and interact with the application.</p>
<p>Update the <code>index.js</code> with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//..</span>

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

  <span class="hljs-comment">// State variables for connection, connect function, and disconnect function</span>
  <span class="hljs-keyword">const</span> [connection, connect, disconnect] = useViewerConnection();


  <span class="hljs-keyword">const</span> [isWindow, setIsWindow] = useState(<span class="hljs-literal">null</span>);


  <span class="hljs-comment">// State variable for viewer's basic profile data</span>
  <span class="hljs-keyword">const</span> record = useViewerRecord(<span class="hljs-string">"basicProfile"</span>);

  <span class="hljs-comment">// Function to create EthereumAuthProvider using window.ethereum provider</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createAuthProvider</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> addresses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">window</span>.ethereum.request({
      <span class="hljs-attr">method</span>: <span class="hljs-string">"eth_requestAccounts"</span>,
    });
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> EthereumAuthProvider(<span class="hljs-built_in">window</span>.ethereum, addresses[<span class="hljs-number">0</span>]);
  }

  <span class="hljs-comment">// Function to connect to viewer's account using created authProvider</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connectAccount</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> authProvider = <span class="hljs-keyword">await</span> createAuthProvider();
    <span class="hljs-keyword">await</span> connect(authProvider);
  }

  <span class="hljs-comment">// Rendered JSX code</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      {/* ... */}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
        {/* ... */}

        {/* Conditionally render a button to connect/disconnect user */}
        {connection.status === "connected" ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> disconnect()}
          &gt;
            Disconnect
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        ) : isWindow &amp;&amp; "ethereum" in window ? (
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{connection.status</span> === <span class="hljs-string">"connecting"</span> || !<span class="hljs-attr">record</span>}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
              connectAccount();
            }}
          &gt;
            Connect Wallet
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        ) : (
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-red-500 text-sm italic mt-2 text-center w-full"</span>&gt;</span>
            An injected Ethereum provider such as{" "}
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://metamask.io/"</span>&gt;</span>MetaMask<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> is needed to
            authenticate.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<p>In the code snippet above,</p>
<ul>
<li>The <code>useViewerConnection</code> hook is used to set up a state variable for the user's connection status, connect and disconnect.</li>
<li><code>isWindow</code> to set the initial state of the the window to avoid <a target="_blank" href="https://nextjs.org/docs/messages/react-hydration-error">React hydration error</a></li>
<li>The <code>useViewerRecord</code> hook is used to retrieve the user's basic profile data.</li>
<li>The <code>createAuthProvider</code> function creates an <code>EthereumAuthProvider</code> object using the <code>window.ethereum</code> provider.</li>
<li>The <code>connectAccount</code> function calls <code>createAuthProvider</code> and connects to the user's account using <code>connect(authProvider)</code>.</li>
<li>The JSX code conditionally renders a button based on the user's connection status and the availability of an <code>ethereum</code> provider in the <code>window</code> object.</li>
<li>If the user is already connected, the button will enable them to disconnect. If the user is not yet connected and an <code>ethereum</code> provider is available, the button will enable them to connect. But if the user is not connected and no <code>ethereum</code> provider is available, a message will be displayed to inform the user that an injected Ethereum provider like MetaMask is required to authenticate.</li>
</ul>
<p>Testing out the authentication functionality, you should have something similar to what is shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676467487656/bc91509c-cd69-479a-80e5-7bc9b680150d.png" alt="Image" width="1561" height="695" loading="lazy"></p>
<h3 id="heading-how-to-create-or-update-a-user-profile">How to Create or Update a User Profile</h3>
<p>In the previous section, you learned how to successfully authenticate users. Next, you will implement functionality to create and update an authenticated user with the following code snippet:</p>
<p><code>pages/index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">//...</span>


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-comment">// Use the useState hook to create state variables and functions to update them</span>
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [bio, setBio] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);

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

<span class="hljs-comment">// Define an asynchronous function called updateProfile to update the profile information</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateProfile</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// If any of the required fields are empty, return early and do not update</span>
     <span class="hljs-keyword">if</span> (!name || !bio || !username) {
       <span class="hljs-keyword">return</span>;
     }

     <span class="hljs-comment">// Use the merge method to update the record with the new information</span>
     <span class="hljs-keyword">await</span> record.merge({
       name,
       bio,
       username,
     });
   }

  <span class="hljs-comment">// Render the component's UI</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>

    {/* ... */}

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center pt-20 font-sans overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-md w-full mx-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-10 rounded-lg shadow-lg"</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">form</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            {connection.status === "connected" &amp;&amp; record &amp;&amp; record.content ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center mt-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold mb-6 text-gray-900"</span>&gt;</span>
                  Profile Information
                <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">className</span>=<span class="hljs-string">"w-full max-w-md bg-white p-8 rounded-lg shadow-lg"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Name:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"nameOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.name || "No name set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Bio:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"bioOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.bio || "No bio set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold text-gray-700 mr-2 text-lg"</span>&gt;</span>
                      Username:
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>{" "}
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"usernameOutput"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>
                      {record.content.username || "No username set"}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            ) : (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-8 rounded-lg shadow-lg"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>No profile found.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            )}

          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  ) 
}
</code></pre>
<p>In the code above,</p>
<ul>
<li>The component uses the useState hook to manage the state of three variables: <code>name</code>, <code>bio</code>, and <code>username</code>.</li>
<li>There's an async function called <code>updateProfile</code> that is responsible for merging the current state of the variables into a record.</li>
<li>If any of the variables is empty, the <code>updateProfile</code> function returns without updating the record.</li>
<li>There are three conditional statements that render a different UI based on whether a record is found or not.</li>
<li>The first conditional statement checks whether the record is still loading, and if it is, it displays a <code>Loading...</code> message.</li>
<li>The second conditional statement checks whether there's no record content and the connection status is connected. If this is true, it displays a <code>No profile found.</code> message.</li>
</ul>
<p>The third conditional statement checks whether the record content exists. If it does, it displays the profile information, which includes the user's <code>name</code>, <code>bio</code>, and <code>username</code>.</p>
<p>You are almost there. In the form tag, update the <code>name</code>, <code>bio</code> and <code>username</code> input field with the following code:</p>
<pre><code class="lang-javascript">&lt;div className=<span class="hljs-string">"mb-6"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>
  &gt;</span>
    Name
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    //<span class="hljs-attr">...</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
      setName(e.target.value);
    }}
  /&gt;</span>
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"bio"</span>
  &gt;</span>
    Bio
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
    //<span class="hljs-attr">...</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
      setBio(e.target.value);
    }}
  &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 font-bold mb-2"</span>
    <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"username"</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">...</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">div</span>&gt;</span></span>
</code></pre>
<p>In the code snippet above, <code>setName</code>, <code>setBio</code>, and <code>setUsername</code> are functions provided by the <code>useState</code> hook that update the state of <code>name</code>, <code>bio</code>, or <code>username</code>.</p>
<p>Next, the <code>Update Profile</code> button.</p>
<pre><code class="lang-xml">//...

 <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
     <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
     <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
     <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!record.isMutable</span> || <span class="hljs-attr">record.isMutating</span>}
     <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updateProfile()}
 &gt;
    {record.isMutating ? "Updating..." : "Update Profile"}
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

//..
</code></pre>
<p>In the code snippet above, the button is disabled when the record is not mutable or is currently mutating. </p>
<p>When the button is clicked, it calls the <code>updateProfile</code> function, which is responsible for updating the user's profile information. If the record mutates, the button will display <code>Updating...</code>. Otherwise, it will display <code>Update Profile</code>.</p>
<p>You can test out the application similar to what is shown below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.loom.com/share/f2103bcb44c949f7bfdbd5cb531b0c71">https://www.loom.com/share/f2103bcb44c949f7bfdbd5cb531b0c71</a></div>
<p>Kindly find the complete code on <a target="_blank" href="https://github.com/Olanetsoft/decentralized-identity-project">GitHub repository here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post, you learn about Decentralized Identity, Decentralized Identifiers, Ceramic networks, why Ceramic network is useful, and how to build a decentralized identity profile with Ethereum on Ceramic Networks.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><a target="_blank" href="https://github.com/ceramicnetwork/ceramic">Ceramic Network</a></li>
<li><a target="_blank" href="https://developers.ceramic.network/reference/">Ceramic Documentation</a></li>
<li><a target="_blank" href="https://ethereum.org/en/decentralized-identity/">Decentralized Identity - Ethereum</a></li>
</ul>
<p>I'd love to connect with you at <a target="_blank" href="https://twitter.com/olanetsoft"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/olubisi-idris-ayinde-05727b17a/"><strong>LinkedIn</strong></a> | <a target="_blank" href="https://github.com/Olanetsoft"><strong>GitHub</strong></a> | <a target="_blank" href="https://idrisolubisi.com/"><strong>Portfolio</strong></a></p>
<p>See you in my next article. Take care!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Next.js Image Tutorial – How to Upload, Crop, and Resize Images in the Browser in Next ]]>
                </title>
                <description>
                    <![CDATA[ Two of the most fundamental image editing functions are resizing and cropping. But you should do these carefully because they have the potential to degrade image quality. Cropping always includes removing a portion of the original image, resulting in... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-upload-crop-resize-images-in-the-browser-in-nextjs/</link>
                <guid isPermaLink="false">66b905da2898aa52dab670af</guid>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Mon, 18 Apr 2022 17:19:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/pexels-cottonbro-5083407.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Two of the most fundamental image editing functions are resizing and cropping. But you should do these carefully because they have the potential to degrade image quality.</p>
<p>Cropping always includes removing a portion of the original image, resulting in the loss of some pixels.</p>
<p>This post will teach you how to upload, crop, and resize images in the browser.</p>
<p>I built this project in a <a target="_blank" href="https://codesandbox.io/s/serverless-leaf-vc9rls?file=/pages/index.js">Codesandbox</a>. To get started quickly, fork the <a target="_blank" href="https://codesandbox.io/s/serverless-leaf-vc9rls?file=/pages/index.js">Codesandbox</a> or run the project.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have some JavaScript and React.js experience. Experience with Next.js isn't a requirement, but it's nice to have.</p>
<p>You also need a <a target="_blank" href="https://cloudinary.com/users/register/free">Cloudinary account</a> to store the media files.</p>
<p><a target="_blank" href="https://cloudinary.com/documentation/image_video_and_file_upload#upload_options_overview">Cloudinary</a> offers a safe and complete API for quickly and efficiently uploading media files from the server, browser, or a mobile application.</p>
<p>Finally you'll need <a target="_blank" href="https://nextjs.org/">Next.js</a>. It's an open-source React-based front-end development web framework that allows server-side rendering and the generation of static websites and applications.</p>
<h2 id="heading-project-setup-and-installation">Project Setup and Installation</h2>
<p>Use the <code>npx create-next-app</code> command to scaffold a new project in a directory of your choice to create a new project.</p>
<p>You can do this with the command:</p>
<pre><code>npx create-next-app &lt;project name&gt;
</code></pre><p>To install the dependencies, use these commands:</p>
<pre><code>cd &lt;project name&gt; 
npm install cloudinary-react
</code></pre><p>Once the app is created, and the dependencies are installed, you'll see a message with instructions for navigating to your site and running it locally.</p>
<p>You can do this with the command:</p>
<pre><code>npm run dev
</code></pre><p>Next.js will start a hot-reloading development environment accessible by default at <code>http://localhost:3000</code>.</p>
<h2 id="heading-how-to-build-the-user-interface">How to Build the User Interface</h2>
<p>For our project, we'll want the user interface to upload, crop, and resize images on the home page. We will do this by updating the <code>pages/index.js</code> file to a component:</p>
<pre><code><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> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

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

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdiv"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-h1"</span>&gt;</span>
            How to Crop, Resize &amp; Upload Image in the Browser using Cloudinary
            Transformation
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdivcard"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-h2"</span>&gt;</span>Resize Options<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftbutton"</span>&gt;</span>
            Upload Image
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rightdiv"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Image will appear here<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span 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> IndexPage;
</code></pre><p>The current user interface doesn't look that great, though. We'll add some styling with CSS in the <code>style.css</code> file like this:</p>
<pre><code>@<span class="hljs-keyword">import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css?family=Acme|Lobster"</span>);

<span class="hljs-comment">/* This allow me to have the full width of the page without the initial padding/margin*/</span>
body,
html {
  <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>;
  padding: <span class="hljs-number">0</span>;
  height: <span class="hljs-number">100</span>%;
  width: <span class="hljs-number">100</span>%;
  font-family: Acme;
  min-width: <span class="hljs-number">700</span>px;
}

.splitdiv {
  <span class="hljs-attr">height</span>: <span class="hljs-number">100</span>%;
  width: <span class="hljs-number">50</span>%;
}

<span class="hljs-comment">/* This part contains all of the left side of the screen */</span>
<span class="hljs-comment">/* ----------------------------------------- */</span>
#leftdiv {
  <span class="hljs-attr">float</span>: left;
  background-color: #fafafa;
  height: <span class="hljs-number">932</span>px;
}

#leftdivcard {
  <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span> auto;
  width: <span class="hljs-number">50</span>%;
  background-color: white;
  margin-top: <span class="hljs-number">25</span>vh;
  transform: translateY(<span class="hljs-number">-50</span>%);
  box-shadow: <span class="hljs-number">10</span>px <span class="hljs-number">10</span>px <span class="hljs-number">1</span>px <span class="hljs-number">0</span>px rgba(<span class="hljs-number">78</span>, <span class="hljs-number">205</span>, <span class="hljs-number">196</span>, <span class="hljs-number">0.2</span>);
  border-radius: <span class="hljs-number">10</span>px;
}

#leftbutton {
  background-color: #<span class="hljs-number">512</span>cf3;
  border-radius: <span class="hljs-number">5</span>px;
  color: #fafafa;
  margin-left: <span class="hljs-number">350</span>px;
}

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

<span class="hljs-comment">/* This part contains all of the right side of the screen */</span>
<span class="hljs-comment">/* ----------------------------------------- */</span>
#rightdiv {
  <span class="hljs-attr">float</span>: right;
  background-color: #cbcfcf;
  height: <span class="hljs-number">932</span>px;
}

#rightdivcard {
  <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span> auto;
  width: <span class="hljs-number">50</span>%;
  margin-top: <span class="hljs-number">50</span>vh;
  transform: translateY(<span class="hljs-number">-50</span>%);
  background-position: bottom;
  background-size: <span class="hljs-number">20</span>px <span class="hljs-number">2</span>px;
  background-repeat: repeat-x;
}

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

<span class="hljs-comment">/* Basic styling */</span>
<span class="hljs-comment">/* ----------------------------------------- */</span>

button {
  <span class="hljs-attr">outline</span>: none !important;
  font-family: Lobster;
  margin-bottom: <span class="hljs-number">15</span>px;
  border: none;
  font-size: <span class="hljs-number">20</span>px;
  padding: <span class="hljs-number">8</span>px;
  padding-left: <span class="hljs-number">20</span>px;
  padding-right: <span class="hljs-number">20</span>px;
  margin-top: <span class="hljs-number">-15</span>px;
  cursor: pointer;
}

h1 {
  font-family: Lobster;
  color: #<span class="hljs-number">512</span>cf3;
  text-align: center;
  font-size: <span class="hljs-number">40</span>px;
}

input {
  font-family: Acme;
  font-size: <span class="hljs-number">16</span>px;
  font-family: <span class="hljs-number">15</span>px;
}

input {
  <span class="hljs-attr">width</span>: <span class="hljs-number">30</span>%;
  height: <span class="hljs-number">20</span>px;
  padding: <span class="hljs-number">16</span>px;
  margin-left: <span class="hljs-number">1</span>%;
  margin-right: <span class="hljs-number">2</span>%;
  margin-top: <span class="hljs-number">15</span>px;
  margin-bottom: <span class="hljs-number">10</span>px;
  display: inline-block;
  border: none;
}

<span class="hljs-attr">input</span>:focus {
  <span class="hljs-attr">outline</span>: none !important;
  border: <span class="hljs-number">1</span>px solid #<span class="hljs-number">512</span>cf3;
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span>px round #<span class="hljs-number">719</span>ece;
}

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

.main {
  <span class="hljs-attr">height</span>: <span class="hljs-number">100</span>%;
  width: <span class="hljs-number">100</span>%;
  display: inline-block;
}

.main-h2 {
  padding-top: <span class="hljs-number">20</span>px;
  text-align: center;
}

.body-h1 {
  padding-top: <span class="hljs-number">20</span>px;
  text-align: center;
  color: white;
}

.inner-p {
  <span class="hljs-attr">color</span>: white;
  text-align: center;
}

.main-align {
  text-align: center;
}

.form-control {
  margin-left: <span class="hljs-number">15</span>px;
}
</code></pre><p>Our application should now look like this on http://localhost:3000/:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650105687298/eeGTDWFHA.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="3360" height="1876" loading="lazy"></p>
<h2 id="heading-how-to-create-the-image-upload-widget">How to Create the Image Upload Widget</h2>
<p>Cloudinary's upload widget lets us upload media assets from multiple sources, including Dropbox, Facebook, Instagram, and images that were taken right from our device's camera. We'll use the upload widget in this project.</p>
<p>Create a free cloudinary account to obtain your cloud name and upload_preset. </p>
<p><code>upload_presets</code> allows us to define a set of asset upload choices centrally rather than providing them in each upload call. A Cloudinary <code>cloud name</code> is a unique identifier associated with your Cloudinary account.</p>
<p>First, from a content delivery network (CDN), we will add the Cloudinary widget's JavaScript file in our <code>index.js</code> located in <code>pages/index.js.</code> We will include this file using <code>next/head</code> to include all meta tags, which lets us add data to the Head portion of our HTML document in React.</p>
<p>Next, in the <code>pages/index.js</code> file, we'll import Head from next/head and add the script file.</p>
<pre><code><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> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

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

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>How to Crop and Resize Image in the Browser<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charSet</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">"https://widget.Cloudinary.com/v2.0/global/all.js"</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</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>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</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> IndexPage;
</code></pre><p>In the <code>pages/index.js</code> file, we will create an instance of the widget in a method triggered when clicking a button and a state variable <code>imagePublicId.</code>.</p>
<pre><code><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> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [imagePublicId, setImagePublicId] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> openWidget = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// create the widget</span>
    <span class="hljs-keyword">const</span> widget = <span class="hljs-built_in">window</span>.cloudinary.createUploadWidget(
      {
        <span class="hljs-attr">cloudName</span>: <span class="hljs-string">"olanetsoft"</span>,
        <span class="hljs-attr">uploadPreset</span>: <span class="hljs-string">"w42epls7"</span>
      },
      <span class="hljs-function">(<span class="hljs-params">error, result</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (
          result.event === <span class="hljs-string">"success"</span> &amp;&amp;
          result.info.resource_type === <span class="hljs-string">"image"</span>
        ) {
          <span class="hljs-built_in">console</span>.log(result.info);
          setImagePublicId(result.info.public_id);
        }
      }
    );
    widget.open(); <span class="hljs-comment">// open up the widget after creation</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      //...
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> IndexPage;
</code></pre><p>The widget requires our Cloudinary <code>cloud_name</code> and <code>uploadPreset.</code> The <code>createWidget()</code> function creates a new upload widget. On successfully uploading an image, we assign the <code>public_id</code> of the asset to the relevant state variable.</p>
<p>To get our <code>cloudname</code> and <code>uploadPreset,</code> we follow the steps below:</p>
<p>You can get the cloud name from your Cloudinary dashboard, as shown below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650106671153/wjBrA3_m0.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="3360" height="1368" loading="lazy"></p>
<p>You can find an upload preset in the <code>Upload</code> tab of your Cloudinary settings page. You access this by clicking on the gear icon in the top right corner of the dashboard page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650106901391/73lFzuxLQ.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="2969" height="232" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650106814185/GqnIFsNYS.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="2653" height="738" loading="lazy"></p>
<p>Scroll down to the bottom of the page to the upload presets section, where you'll see your upload preset or the option to create one if you don't have any.</p>
<p>We'll proceed to call the <code>openWidget</code> function in the <code>onClick</code> handler of our image upload button, as shown below:</p>
<pre><code><span class="hljs-comment">//...</span>

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-comment">//...</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
     //....
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdiv"</span>&gt;</span>
          //...
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdivcard"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-h2"</span>&gt;</span>Resize Options<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
             //...
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftbutton"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{openWidget}</span>&gt;</span>
            Upload Image
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rightdiv"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Image will appear here<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span 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> IndexPage;
</code></pre><p>When we open our app in the browser and click the <code>Upload Image</code> button, we should see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650111448538/pglrS-Exs.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="3360" height="1881" loading="lazy"></p>
<h2 id="heading-how-to-implement-custom-transformation-functions">How to Implement Custom Transformation Functions</h2>
<p>We need to create a component that handles the transformation depending on the props passed to it. We will create a <code>components/</code> directory in the root folder. Inside it, we will create a file called <code>image.js</code> with the following content:</p>
<pre><code><span class="hljs-keyword">import</span> { CloudinaryContext, Transformation, Image } <span class="hljs-keyword">from</span> <span class="hljs-string">"cloudinary-react"</span>;

<span class="hljs-keyword">const</span> TransformImage = <span class="hljs-function">(<span class="hljs-params">{ crop, image, width, height }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">CloudinaryContext</span> <span class="hljs-attr">cloudName</span>=<span class="hljs-string">"olanetsoft"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">publicId</span>=<span class="hljs-string">{image}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Transformation</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span> <span class="hljs-attr">crop</span>=<span class="hljs-string">{crop}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Image</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">CloudinaryContext</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TransformImage;
</code></pre><p>In the code snippet above, we imported <code>CloudinaryContext</code>, a wrapper Cloudinary component used to manage shared information across all its children Cloudinary components. The rendered <code>TransformImage</code> component takes data of the image transformation as props.</p>
<p>The above code block will render the uploaded image when we import it into <code>pages/index.js</code>:</p>
<pre><code><span class="hljs-comment">//...</span>
<span class="hljs-keyword">import</span> TransformImage <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/image"</span>;

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [imagePublicId, setImagePublicId] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [alt, setAlt] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [crop, setCrop] = useState(<span class="hljs-string">"scale"</span>);
  <span class="hljs-keyword">const</span> [height, setHeight] = useState(<span class="hljs-number">200</span>);
  <span class="hljs-keyword">const</span> [width, setWidth] = useState(<span class="hljs-number">200</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
     //...
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdiv"</span>&gt;</span>
          //...
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rightdiv"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Image will appear here<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rightdivcard"</span>&gt;</span>
            {imagePublicId ? (
              <span class="hljs-tag">&lt;<span class="hljs-name">TransformImage</span>
                <span class="hljs-attr">crop</span>=<span class="hljs-string">{crop}</span>
                <span class="hljs-attr">image</span>=<span class="hljs-string">{imagePublicId}</span>
                <span class="hljs-attr">width</span>=<span class="hljs-string">{width}</span>
                <span class="hljs-attr">height</span>=<span class="hljs-string">{height}</span>
              /&gt;</span>
            ) : (
              <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Image will appear here<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            )}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> IndexPage;
</code></pre><p>Next, we will add the <code>Resize Options</code> radio button so that we can select different resize and crop options with the following code snippet:</p>
<pre><code><span class="hljs-comment">//...</span>

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> {
<span class="hljs-comment">//...</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    //...
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdiv"</span>&gt;</span>
          //...
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftdivcard"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-h2"</span>&gt;</span>Resize Options<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control"</span>&gt;</span>Select Crop Type<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">className</span>=<span class="hljs-string">"form-control"</span>&gt;</span>Scale<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">"radio"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">"scale"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"crop"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setCrop(event.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>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-control"</span>&gt;</span>Crop<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">"radio"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">"crop"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"crop"</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setCrop(event.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">input</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
              <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Height"</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setHeight(event.target.value)}
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span>
              <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Width"</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(event)</span> =&gt;</span> setWidth(event.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">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"leftbutton"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{openWidget}</span>&gt;</span>
            Upload Image
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"splitdiv"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"rightdiv"</span>&gt;</span>
          //...
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> IndexPage;
</code></pre><p>In the code snippet above, we:</p>
<ul>
<li>Added crop type and also width and height options</li>
<li>Added an <code>onChange</code> property to keep track of the changes in the height and width input field, respectively</li>
</ul>
<p>Our application's final output should look similar to what we have below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650112568692/2htjubfOv.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="3360" height="1882" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650112581661/JnEP--CHC.png" alt="How to Upload, Crop, &amp; Resize Image in the Browser in Next.js" width="3360" height="1874" loading="lazy"></p>
<p>Here's the GitHub Repository for the project if you want to have a look at the full code: <a target="_blank" href="https://github.com/Olanetsoft/how-to-upload-crop-and-resize-images-in-the-browser-in-next.js">https://github.com/Olanetsoft/how-to-upload-crop-and-resize-images-in-the-browser-in-next.js</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This post shows how to upload, crop, and resize images in the browser in Next.js.</p>
<h2 id="heading-resources">Resources</h2>
<p> You may find these resources helpful.</p>
<ul>
<li><a target="_blank" href="https://cloudinary.com/documentation/transformation_reference">Cloudinary transformation URL reference</a></li>
<li><a target="_blank" href="https://cloudinary.com/documentation/image_transformations">Cloudinary Image Transformation</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Full Stack Application With Supabase, React, and Tailwind CSS in Nextjs ]]>
                </title>
                <description>
                    <![CDATA[ Serverless databases are all the rage these days. They allow you to develop a fully functional app without building a server or writing server code.  A serverless database is a cloud computing solution that lets you distribute and flexibly manage you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-full-stack-application-with-tailwind-css-and-supabase-in-nextjs/</link>
                <guid isPermaLink="false">66b905d45730a049b6bfea7f</guid>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Wed, 26 Jan 2022 23:03:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/pexels-luis-gomes-546819.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Serverless databases are all the rage these days. They allow you to develop a fully functional app without building a server or writing server code. </p>
<p>A serverless database is a cloud computing solution that lets you distribute and flexibly manage your resources.</p>
<p>In this tutorial, we'll build a full-stack application with Supabase, React, and TailwindCSS in Next.js.</p>
<h3 id="heading-outline">Outline</h3>
<ul>
<li>What is Supabase?</li>
<li>Why Should You Use Supabase?</li>
<li>How to Set Up a Supabase Project</li>
<li>How to Set Up Our Frontend Application</li>
<li>How to Build Our Frontend Application Layout with the Supabase Client</li>
<li>How to Build Our Application</li>
<li>Conclusion</li>
<li>Resources</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Practical React.js experience</li>
<li>A basic grasp of async functions</li>
<li>A GitHub account</li>
</ul>
<h2 id="heading-what-is-supabase">What Is Supabase?</h2>
<p><a target="_blank" href="https://supabase.io">Supabase</a> is a PostgreSQL-based open-source serverless database that allows you to build a real-time backend for your application in a few minutes.</p>
<p>PostgreSQL is an object-relational database system that has been actively developed for more than 25 years and is known for its dependability and performance.</p>
<p><a target="_blank" href="https://supabase.io">Supabase</a> includes several out-of-the-box services/functionalities that are designed to make your life easier. These include the following, but are not limited to:</p>
<ul>
<li>Authentication</li>
<li>Realtime Database</li>
<li>UI components</li>
<li>RLS (Row Level Security)</li>
</ul>
<h3 id="heading-why-should-you-use-supabase">Why Should You Use Supabase?</h3>
<ul>
<li>Supabase takes care of the scaling (even though it uses an SQL database).</li>
<li>Although Supabase is based on PostgreSQL, data migration is easy.</li>
<li>You can run complicated queries or text searches, unlike with Firebase.</li>
</ul>
<h2 id="heading-step-1-how-to-set-up-a-supabase-project">Step 1: How to Set Up a Supabase Project</h2>
<p>This section will build our project and integrate Supabase into our application.</p>
<h3 id="heading-sign-up-for-a-supabase-account-and-create-a-project">Sign up for a Supabase account and create a project</h3>
<p>To get started, let's sign up for a Supabase account <a target="_blank" href="https://api.supabase.io/platform/login">here</a>. To continue, you'll need a GitHub account. You can register <a target="_blank" href="http://github.com">here</a> if you don't yet have an account on GitHub.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/welcome-screen.png" alt="Supabase Dashboard - welcome-screen" width="600" height="400" loading="lazy"></p>
<p>After we've logged in, we're redirected to our dashboard, as shown in the screenshot above.</p>
<p>Next, we can now click on the <code>New Project</code> Button to create a new project for our demo application, as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/create-project.png" alt="Supabase Dashboard - create-project" width="600" height="400" loading="lazy"></p>
<p>Then we'll see the screen below, which shows us that the project is now being built.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/project-setup.png" alt="Supabase Dashboard - project-setup" width="600" height="400" loading="lazy"></p>
<p>Next, we'll need to create our database by clicking the database icon shown on the sidebar. We also need to click the plus icon shown on the top right of the screen to make each column we need, as shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/database.png" alt="Supabase Dashboard - database" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-the-columns-required-for-our-application">How to create the columns required for our application</h3>
<p>For this todo project, we will be creating five columns:</p>
<ul>
<li><code>Name</code>: This is the task's name with the type of <code>text.</code>
<code>Activity</code>: This is the task's activity related to the type of <code>text.</code></li>
<li><code>StartDate</code>: This is when the task is expected to start with the type of <code>date.</code></li>
<li><code>EndDate</code>: This is the date that the task is expected to end with the type of <code>date.</code></li>
</ul>
<p>After creating all these fields, we should have something similar to what we have below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/database-table.png" alt="Supabase Dashboard - database-table" width="600" height="400" loading="lazy"></p>
<p>We have created our project and created individual columns. We will proceed to the next step by setting up our frontend application in the next section.</p>
<h2 id="heading-step-2-setting-up-our-frontend-application">Step 2: Setting Up Our Frontend Application</h2>
<p>To create a new project, we use the <code>npx create-next-app -e with-tailwindcss .</code> command to scaffold a new project in a directory of our choice.</p>
<p>The command specified above sets up a TailwindCSS project in Next.js.</p>
<p><a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a> is a CSS framework containing a lot of classes to help us style our website.</p>
<p>We use the following commands to install the dependencies:</p>
<pre><code class="lang-Bash">    <span class="hljs-built_in">cd</span> &lt;project name&gt; 
    yarn add @supabase/supabase-js
</code></pre>
<p>We'll see a message with instructions for browsing our site and running it locally after the app is created and the dependencies have been installed. Using the below command, we can execute this.</p>
<pre><code class="lang-Bash">    npm run dev
</code></pre>
<p>Next.js will start a hot-reloading development environment accessible by default at <a target="_blank" href="http://localhost:3000">http://localhost:3000</a>.</p>
<p>We should see something similar to what we have below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/next-welcome.png" alt="nextjs-welcome-page" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-3-building-our-frontend-application-layout-with-the-supabase-client">Step 3: Building Our Frontend Application Layout with the Supabase Client</h2>
<p>We can now build our front-end application since we have completed our front-end setup.</p>
<p>Let's update our <code>pages/index.js</code> file to include the following code:</p>
<pre><code class="lang-Javascript"><span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center py-2"</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">Head</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Supabase and NextJs Demo<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center w-full flex-1 px-20 text-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl font-bold mt-20"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-blue-600"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>
              Full Stack Application With Tailwind CSS and Supabase in NextJs
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-8 mt-6 border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full max-w-sm"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded px-8 pt-6 pb-8 mb-4"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"taskName"</span>
                    &gt;</span>
                      Task 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">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"taskName"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"taskActivity"</span>
                    &gt;</span>
                      Task Activity
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"form-textarea mt-1 block shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">rows</span>=<span class="hljs-string">"3"</span>
                      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Task Activity"</span>
                    &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"startDate"</span>
                    &gt;</span>
                      Task Start Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"startDate"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                    /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"endDate"</span>
                    &gt;</span>
                      Task End Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"endDate"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                    /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                    &gt;</span>
                      Add Task
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 mt-6 w-96 rounded-xl focus:text-blue-600"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow-lg bg-white"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-4 py-4"</span>&gt;</span>
                      S/N
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-8 py-4"</span>&gt;</span>
                      Name
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-8 py-4"</span>&gt;</span>
                      Activity
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-14 py-4"</span>&gt;</span>
                      Start Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-16 py-4"</span>&gt;</span>
                      End Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-4 py-4"</span>&gt;</span>
                      Action
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-4 py-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-4 py-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span>
                      {" "}
                      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"</span>
                        <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</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">td</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">table</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">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>We added a layout for our application in the code snippet above, and we styled it with TailwindCSS.</p>
<p>We should have something similar to what we have below if we visit our application in the browser.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/updated-index.png" alt="NextJs Supabase - updated-index" width="600" height="400" loading="lazy"></p>
<p>We'll use the <code>Supabase</code> package to link our application to our database. Using environment variables is the best approach for us to configure this.</p>
<p>You can set environment variables in Next.js by creating a file called <code>.env</code> in the project's root directory and saving them there.</p>
<p>It's best to precede a variable with <code>NEXT_PUBLIC_</code> to expose it to the browser.</p>
<p>Add the following configuration to a file called <code>.env</code> in the project's root directory:</p>
<pre><code>NEXT_PUBLIC_SUPABASE_URL=https:<span class="hljs-comment">//app-id.supabase.co</span>
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-public-api-key
</code></pre><p>We can find the values of our API URL and API Key in the Supabase dashboard settings, as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/api-1.png" alt="NexJs Index" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/api-2.png" alt="NextJs Index Result" width="600" height="400" loading="lazy"></p>
<p>Next, we will create a file called <code>client.js</code> in the root of the project and then add the following code:</p>
<pre><code>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_TOKEN
);
</code></pre><p>After importing it, we can now utilize the Supabase instance everywhere in our app.</p>
<h2 id="heading-step-4-building-our-application">Step 4: Building our Application</h2>
<p>Let's update our <code>pages/index.js</code> file so that we can add a new task using the Supabase instance with the following code:</p>
<pre><code class="lang-Javascript"><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../client"</span>;

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

  <span class="hljs-comment">// Declare a new state variable to store task details</span>
  <span class="hljs-keyword">const</span> [task, setTask] = useState({
    <span class="hljs-attr">Name</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">Activity</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">StartDate</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">EndDate</span>: <span class="hljs-string">""</span>,
  });

  <span class="hljs-keyword">const</span> { Name, Activity, StartDate, EndDate } = task;

  <span class="hljs-comment">// Create a function that handles the new task creation</span>
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTask</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">"Task"</span>) <span class="hljs-comment">// Select the Table</span>
      .insert([
        {
          Name,
          Activity,
          StartDate,
          EndDate,
        },
      ]) <span class="hljs-comment">// Insert the new task</span>
      .single();
    setTask({
      <span class="hljs-attr">Name</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">Activity</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">StartDate</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">EndDate</span>: <span class="hljs-string">""</span>,
    }); <span class="hljs-comment">// Reset the task details</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">"flex flex-col items-center justify-center py-2"</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">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center w-full flex-1 px-20 text-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl font-bold mt-20"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-blue-600"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>
              Full Stack Application With Tailwind CSS and Supabase in NextJs
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-8 mt-6 border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full max-w-sm"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded px-8 pt-6 pb-8 mb-4"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"taskName"</span>
                    &gt;</span>
                      Task 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">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"taskName"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                      <span class="hljs-attr">value</span>=<span class="hljs-string">{Name.toString()}</span>
                      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
                        setTask({ ...task, Name: e.target.value })
                      }
                    /&gt;
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"taskActivity"</span>
                    &gt;</span>
                      Task Activity
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"form-textarea mt-1 block shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">rows</span>=<span class="hljs-string">"3"</span>
                      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Task Activity"</span>
                      <span class="hljs-attr">value</span>=<span class="hljs-string">{Activity.toString()}</span>
                      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
                        setTask({ ...task, Activity: e.target.value })
                      }
                    &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"startDate"</span>
                    &gt;</span>
                      Task Start Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"startDate"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                      <span class="hljs-attr">value</span>=<span class="hljs-string">{StartDate.toString()}</span>
                      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
                        setTask({ ...task, StartDate: e.target.value })
                      }
                    /&gt;
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-gray-700 text-sm font-bold mb-2"</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"endDate"</span>
                    &gt;</span>
                      Task End Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">id</span>=<span class="hljs-string">"endDate"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                      <span class="hljs-attr">value</span>=<span class="hljs-string">{EndDate.toString()}</span>
                      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span>
                        setTask({ ...task, EndDate: e.target.value })
                      }
                    /&gt;
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-between"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"</span>
                      <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addTask}</span> // <span class="hljs-attr">Call</span> <span class="hljs-attr">the</span> <span class="hljs-attr">addTask</span> <span class="hljs-attr">Function</span>
                    &gt;</span>
                      Add Task
                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 mt-6 w-96 rounded-xl focus:text-blue-600"</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">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code snippet above, we created a function called <code>AddTask</code> to add a new task using the Supabase instance. We also referenced it in the onClick attribute of our <code>AddTask</code> Button.</p>
<p>Next, after testing our application, you might notice that nothing happens after entering the task details and clicking on the button <code>Add Task</code>. This is because we have not handled task retrieval from our database.</p>
<p>Let's update our <code>pages/index.js</code> file to be able to retrieve all the tasks from our database as shown below:</p>
<pre><code class="lang-Javascript"><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">const</span> [tasks, setTasks] = useState([]);

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

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTasks</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> supabase.from(<span class="hljs-string">"Task"</span>).select(); <span class="hljs-comment">// Select all the tasks from the Task Table</span>
    setTasks(data);
    setLoading(<span class="hljs-literal">false</span>);
  }

  <span class="hljs-comment">// Run the getTasks function when the component is mounted</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    getTasks();
  }, []);

  <span class="hljs-comment">// Check if loading</span>
  <span class="hljs-keyword">if</span> (loading)
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"
      animate-spin
      rounded-full
      h-32
      w-32
      border-t-2 border-b-2 border-blue-500 mt-36
    "</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">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center py-2"</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">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center w-full flex-1 px-20 text-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl font-bold mt-20"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-blue-600"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>
              Full Stack Application With Tailwind CSS and Supabase in NextJs
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-8 mt-6 border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"</span>&gt;</span>
              // ...
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 mt-6 w-96 rounded-xl focus:text-blue-600"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"shadow-lg bg-white"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-4 py-4"</span>&gt;</span>
                      S/N
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-8 py-4"</span>&gt;</span>
                      Name
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-8 py-4"</span>&gt;</span>
                      Activity
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-14 py-4"</span>&gt;</span>
                      Start Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-16 py-4"</span>&gt;</span>
                      End Date
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>

                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-400 border text-left px-4 py-4"</span>&gt;</span>
                      Action
                    <span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                  {task &amp;&amp;
                    tasks.map((task, index) =&gt; (
                      <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-4 py-4"</span>&gt;</span>{index + 1}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-4 py-4"</span>&gt;</span>{task.Name}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span>{task.Activity}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span>{task.StartDate}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span>{task.EndDate}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"border px-8 py-4"</span>&gt;</span>
                          {" "}
                          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</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">td</span>&gt;</span>
                      <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
                    ))}
                <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">table</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">main</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
  );
}
</code></pre>
<p>We created a function called <code>getTasks</code> to retrieve all the tasks added using the Supabase instance. We also iterated all the tasks retrieved displayed all the records in a table format, as shown in the code snippet above.</p>
<p>Let's test our application, and we should be able to add a new task and see all of the tasks we've created so far.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/app-result.png" alt="NextJs App Result" width="600" height="400" loading="lazy"></p>
<p>It works! But we had to refresh the page when a new task was added to see the new task. We don't want that. Let's update our <code>addTask</code> function with the code snippet below:</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">addTask</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">await</span> supabase
      .from(<span class="hljs-string">"Task"</span>)
      .insert([
        {
          Name,
          Activity,
          StartDate,
          EndDate,
        },
      ])
      .single();
    setTask({
      <span class="hljs-attr">Name</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">Activity</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">StartDate</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">EndDate</span>: <span class="hljs-string">""</span>,
    });
    getTasks(); <span class="hljs-comment">// Refresh the tasks</span>
  }
</code></pre>
<p>We will now see a new task added to our task table without refreshing the page.</p>
<p>Let's make the <code>Delete</code> Button that appears on the right side of the table to delete the task from our database.</p>
<p>Update our <code>pages/index.js</code> file with the following snippet:</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">deleteTask</span>(<span class="hljs-params">id</span>) </span>{
    <span class="hljs-keyword">await</span> supabase.from(<span class="hljs-string">"Task"</span>).delete().eq(<span class="hljs-string">"id"</span>, id); <span class="hljs-comment">// the id of row to delete</span>
    getTasks();
  }
</code></pre>
<p>Update the delete button onClick attribute as shown below:</p>
<pre><code class="lang-Javascript">     <span class="hljs-comment">// ...</span>

      &lt;button
        className=<span class="hljs-string">"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"</span>
        type=<span class="hljs-string">"button"</span>
        onClick={<span class="hljs-function">() =&gt;</span> deleteTask(task.id)} <span class="hljs-comment">// Delete the task</span>
       &gt;
        Delete
      &lt;/button&gt;
</code></pre>
<p>When we test our application, we should add a new task, get all the tasks added, and delete any task we want. We can see how it should look in the image below, where we deleted one of the tasks we created earlier.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/final-result.png" alt="NextJs-Supabase-result" width="600" height="400" loading="lazy"></p>
<p>You can <a target="_blank" href="https://github.com/Olanetsoft/supabase-and-nextjs-demo">click here</a> to check out the complete code on GitHub.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This tutorial showed you how to build a full-stack application with Supabase, React, and TailwindCSS in Next.js.</p>
<p>Happy coding!</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://supabase.io/docs/">Supabase Docs</a></li>
<li><a target="_blank" href="https://nextjs.org/">NextJs Docs</a></li>
<li><a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Ansible? A Tool to Automate Parts of Your Job ]]>
                </title>
                <description>
                    <![CDATA[ Hello everyone, today we will talk about Ansible, a fantastic software tool that allows you to automate cross-platform computer support in a simple but effective way. Table of Contents What is Ansible? How Does Ansible Work? Ansible's Architecture P... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-ansible/</link>
                <guid isPermaLink="false">66b905e0472b70138041a589</guid>
                
                    <category>
                        <![CDATA[ ansible ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Fri, 29 Oct 2021 20:42:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/ansble.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello everyone, today we will talk about Ansible, a fantastic software tool that allows you to automate cross-platform computer support in a simple but effective way.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li>What is Ansible?</li>
<li>How Does Ansible Work?</li>
<li>Ansible's Architecture<ul>
<li>Plugins</li>
<li>Modules</li>
<li>Inventories</li>
<li>Playbook</li>
</ul>
</li>
<li>Benefits of Using Ansible</li>
<li>Why is Ansible so important?</li>
<li>How to Install and Configure Ansible on Ubuntu</li>
<li>Conclusion</li>
<li>References</li>
</ul>
<h2 id="heading-what-is-ansible">What is Ansible?</h2>
<p>Ansible is a tool that generates written instructions for automating IT professionals' work throughout the entire system infrastructure.</p>
<p>It's designed particularly for IT professionals who use it for application deployment, configuration management, intra-service orchestration, and practically anything else a systems administrator does on a weekly or daily basis. </p>
<p>Ansible is simple to install because it doesn't require any agent software or other security infrastructure.</p>
<p>While Ansible is at the cutting edge of automation, systems administration, and DevOps, it's also valuable as a tool for devs to use in their daily work. </p>
<p>Ansible allows you to set up not just one machine but a complete network of them all at once, and it doesn't require any programming knowledge.</p>
<h2 id="heading-how-does-ansible-work">How Does Ansible Work?</h2>
<p>Ansible connects to nodes on a network (clients, servers, etc.) and then send a little program called an Ansible module to each node. </p>
<p>It then runs these modules through SSH and deletes them once they're done. </p>
<p>Your Ansible control node must have login access to the managed nodes for this interaction to work. </p>
<p>The most frequent method of authentication is SSH keys, but alternative methods are also allowed.</p>
<p>If you want to see how to install and start using Ansible, we'll cover that below.</p>
<h2 id="heading-ansibles-architecture">Ansible's Architecture</h2>
<p>Now let's take a look at Ansible's architecture and how it manages operations.</p>
<h3 id="heading-ansible-plugins">Ansible Plugins</h3>
<p>Plugins are supplementary pieces of code that enhance functionality, and you've probably used them in many other tools and platforms. You can use Ansible's built-in plugins or create your own. </p>
<p>Examples are: </p>
<ul>
<li>Action Plugins</li>
<li>Become Plugins</li>
<li>Cache Plugins</li>
<li>Callback Plugins</li>
<li>Cliconf Plugins</li>
<li>Connection Plugins</li>
<li>HTTP API Plugins</li>
<li>Inventory Plugins</li>
<li>Lookup Plugins</li>
<li>Netconf Plugins</li>
<li>Tests</li>
</ul>
<h3 id="heading-ansible-modules">Ansible Modules</h3>
<p>Modules are short programs that Ansible distributes to all nodes or remote hosts from a central control workstation. Modules control things like services and packages and can be executed via playbooks. </p>
<p>Ansible runs all of the modules needed to install updates or complete whatever operation is required and then removes them after they're done.</p>
<h3 id="heading-ansible-inventories">Ansible Inventories</h3>
<p>Ansible uses an inventory file to track which hosts are part of your infrastructure and then accesses them to perform commands and playbooks.</p>
<p>Ansible works in parallel with various systems in your infrastructure. It accomplishes this by picking methods mentioned in Ansible's inventory file, which is saved in the host location by default.</p>
<p>Once the inventory is registered, you can use a simple text file to assign variables to any of the hosts, and you may retrieve inventory from a variety of sources. </p>
<h3 id="heading-ansible-playbook">Ansible Playbook</h3>
<p>IT professionals can use Ansible playbooks to program applications, services, server nodes, and other devices without starting from scratch. Ansible playbooks, along with the conditions, variables, and tasks included within them, can be stored, shared, and reused forever.</p>
<p>Ansible playbooks function similarly to task manuals. They're simple <a target="_blank" href="https://en.wikipedia.org/wiki/YAML">YAML</a> files, a human-readable data serialization language. </p>
<p>Playbooks are at the heart of what makes Ansible so popular. They specify activities that can be completed quickly without requiring the user to know or remember any specific syntax.</p>
<h2 id="heading-benefits-of-using-ansible">Benefits of Using Ansible</h2>
<ul>
<li>Ansible is quick and easy to use, as it runs all of its operations over SSH and doesn't require the installation of any agents.</li>
<li>Ansible is a free, open-source tool, and it's straightforward to set up and use: Ansible's playbooks don't require any special coding knowledge.</li>
<li>Ansible can be used to perform simple tasks such as ensuring that a service is operating or rebooting from the command line without the need for configuration files.</li>
</ul>
<p>In a more extensive or more uniform system, Ansible may be a better fit. It also provides a set of modules for managing various methods and cloud infrastructure.</p>
<h2 id="heading-why-is-ansible-so-important">Why is Ansible so important?</h2>
<p>Modernization and digital transformation require automation that's both necessary and purposeful. We need a new management solution in today's dynamic contexts to increase speed, scale, and stability throughout IT infrastructure.</p>
<p>Technology is our most potent instrument for product improvement. Previously, accomplishing this required a significant amount of manual labor and intricate coordination. But today, Ansible - a simple yet powerful IT automation engine used by thousands of enterprises to simplify their setups and speed DevOps operations - is available.</p>
<h2 id="heading-how-to-install-ansible-on-ubuntu">How to Install Ansible on Ubuntu</h2>
<p>Run the following commands to configure the PPA on your machine and install Ansible:</p>
<p>Update the repository:</p>
<pre><code>sudo apt-get update
</code></pre><p>Install the software properties:</p>
<pre><code>sudo apt-get install software-properties-common
</code></pre><p>And then install Ansible like this:</p>
<pre><code>sudo apt-add-repository --yes --update ppa:ansible/ansible
</code></pre><p>Then run this:</p>
<pre><code>sudo apt-get install ansible
</code></pre><p>You should have something similar to what is shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/ansible_installation.png" alt="ansible_installation" width="600" height="400" loading="lazy"></p>
<p>Now that you have successfully installed Ansible, let's test if it's working by using the command below:</p>
<pre><code>ansible --version
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/10/ansible_check.png" alt="ansible_check" width="600" height="400" loading="lazy"></p>
<p>We'll use the command below to instruct Ansible to target all systems for the inventory host localhost, and we'll run the module ping from your local console (rather than ssh).</p>
<pre><code>ansible all -i localhost, --connection=local -m ping
</code></pre><p>You should get a response similar to what you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/ansible_ping.png" alt="ansible_ping" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-modify-the-hosts-that-ansible-targets">How to modify the hosts that Ansible targets</h3>
<p>We'll make changes to the host's file in <code>/etc/ansible/hosts</code>. This is the default file where Ansible searches for any defined hosts (and groups) where the given commands should be executed remotely.</p>
<pre><code>sudo nano /etc/ansible/hosts
</code></pre><p>Add the lines below to the file and save the modifications:</p>
<pre><code>[local]
localhost
</code></pre><p>Execute this command with your adjusted inventory file:</p>
<pre><code>ansible all --connection=local -m ping
</code></pre><p>The response should look similar to what we have below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/ansible_pong.png" alt="ansible_pong" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-configure-a-remote-server">How to configure a remote server</h3>
<p>We deploy our Ansible test program to our remote server using a Digital Ocean droplet.</p>
<p>Use the command below to ssh into the server:</p>
<pre><code>ssh username@IP_Address
</code></pre><blockquote>
<p>Note: we have already configured an ssh key in our profile, which was selected when creating the droplet.</p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/ansible_server.png" alt="ansible_server" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-configure-ansible-for-a-remote-server">How to configure Ansible for a remote server</h3>
<p>We will edit our hosts file in /etc/ansible/hosts using the command below:</p>
<pre><code>sudo nano /etc/ansible/hosts
</code></pre><p>Add the lines below to the file and save the modifications:</p>
<pre><code>[remote]
remote_test

[remote:vars]
ansible_host=IP_ADDRESS_OF_VIRTUAL_MACHINE
ansible_user=USERNAME
</code></pre><p>To see if Ansible can connect to your remote compute instance over SSH, let's type the following command:</p>
<pre><code>ansible remote -m ping
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/10/asnible_result.png" alt="asnible_result" width="600" height="400" loading="lazy"></p>
<p>We'll make an Ansible playbook using the command below, which is the typical way of telling Ansible which commands to run on the remote server and in what order. The playbook is written in .yml and follows a strict format. </p>
<p>In the official <a target="_blank" href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html">Ansible documentation</a>, you can learn more about playbooks.</p>
<pre><code>nano my-playbook.yml
</code></pre><p>Add the following code, which tells Ansible to install Docker in several steps:</p>
<pre><code>---
- name: install docker
<span class="hljs-attr">hosts</span>: remote
<span class="hljs-attr">become_method</span>: sudo
<span class="hljs-attr">become_user</span>: root
<span class="hljs-attr">vars</span>: #local variables
<span class="hljs-attr">docker_packages</span>:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common

<span class="hljs-attr">tasks</span>:
- name: Update apt packages
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span> #make sure you execute the task <span class="hljs-keyword">with</span> sudo privileges
<span class="hljs-attr">apt</span>: #use apt <span class="hljs-built_in">module</span>
<span class="hljs-attr">update_cache</span>: yes #equivalent <span class="hljs-keyword">of</span> apt-get update

- name: Install packages needed <span class="hljs-keyword">for</span> Docker
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span>
<span class="hljs-attr">apt</span>:
name: <span class="hljs-string">"{{ docker_packages }}"</span> #uses our declared variable docker_packages
<span class="hljs-attr">state</span>: present #indicates the desired package state
<span class="hljs-attr">force_apt_get</span>: yes #forces to use apt-get

- name: Add official GPG key <span class="hljs-keyword">of</span> Docker
<span class="hljs-attr">shell</span>: curl -fsSL https:<span class="hljs-comment">//download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</span>

- name: Save the current Ubuntu release version into a variable
<span class="hljs-attr">shell</span>: lsb_release -cs
<span class="hljs-attr">register</span>: ubuntu_version #Output gets stored <span class="hljs-keyword">in</span> <span class="hljs-built_in">this</span> variable

- name: <span class="hljs-built_in">Set</span> right Docker directory
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span>
<span class="hljs-attr">shell</span>: add-apt-repository <span class="hljs-string">"deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ubuntu_version.stdout }} stable"</span>

- name: Update apt packages
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span>
<span class="hljs-attr">apt</span>:
update_cache: yes

- name: Install Docker
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span>
<span class="hljs-attr">apt</span>:
name: docker-ce
<span class="hljs-attr">state</span>: present
<span class="hljs-attr">force_apt_get</span>: yes

- name: Test Docker <span class="hljs-keyword">with</span> hello world example
<span class="hljs-attr">become</span>: <span class="hljs-literal">true</span>
<span class="hljs-attr">shell</span>: docker run hello-world
<span class="hljs-attr">register</span>: hello_world_output

- name: Show output <span class="hljs-keyword">of</span> hello word example
<span class="hljs-attr">debug</span>: #use debug <span class="hljs-built_in">module</span>
<span class="hljs-attr">msg</span>: <span class="hljs-string">"Container Output: {{hello_world_output.stdout}}"</span>
</code></pre><p>We can now execute it with the command below:</p>
<pre><code>ansible-playbook my-playbook.yml -l remote
</code></pre><p>After that, we'll see some magic happen (it might take a while), and somewhere in the last debug message in our terminal, we should see "Hello from Docker!"</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we had a detailed look into Ansible, its benefits, how it works and what it can do, its architecture, plugins, playbook, inventory, and how to configure and deploy Docker with Ansible on a remote server.</p>
<p>Thank you for reading!</p>
<h2 id="heading-resources">Resources</h2>
<p><a target="_blank" href="https://docs.ansible.com/">Ansible docs</a>
<a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-ansible-inventories">Setting up Ansible Inventories</a>
<a target="_blank" href="https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html">Ansible installation</a></p>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/olanetsoft">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/olubisi-idris-ayinde-05727b17a/">LinkedIn</a> | <a target="_blank" href="https://github.com/Olanetsoft">GitHub</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Authenticate Users and Implement CORS in Node.js Apps ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to authenticate users and secure endpoints in Node.js. You'll also see how to implement Cross-Origin Resource Sharing (CORS) in Node. So let's get started. Prerequisites You'll need the following to follow along w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-authenticate-users-and-implement-cors-in-nodejs-applications/</link>
                <guid isPermaLink="false">66b905d1e8c4e204927a90ea</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CORS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Tue, 06 Jul 2021 16:02:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-27-at-00.10.45.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to authenticate users and secure endpoints in Node.js. You'll also see how to implement Cross-Origin Resource Sharing (CORS) in Node. So let's get started.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You'll need the following to follow along with this tutorial: </p>
<ul>
<li>A working understanding of JavaScript.</li>
<li>A good understanding of Node.js.</li>
<li>A working knowledge of MongoDB or another database of your choice.</li>
<li><a target="_blank" href="https://www.postman.com/">Postman</a> and a basic understanding of how it works.</li>
</ul>
<p>Before we jump into the main part of the article, let's define some terms so we're all on the same page.</p>
<h2 id="heading-what-is-authentication">What is Authentication?</h2>
<p>Authentication and authorization may seem like the same thing. But there's a big difference between getting into a house (authentication) and what you can do once you're there (authorization).</p>
<p>Authentication is the process of confirming a user's identity by obtaining credentials and using those credentials to validate their identity. If the certificates are valid, the authorization procedure begins.</p>
<p>You are probably already familiar with the authentication process, because we all go through it daily – whether at work (logging onto your computer) or at home (passwords or logging into a website). In fact, most "things" connected to the Internet require you to provide credentials to prove your identity.</p>
<h2 id="heading-what-is-authorization">What is Authorization?</h2>
<p>Authorization is the process of granting authenticated users access to resources by verifying whether they have system access permissions or not. It also allows you to restrict access privileges by granting or denying specific licenses to authenticated users.</p>
<p>After the system authenticates your identity, authorization occurs, providing you full access to resources such as information, files, databases, finances, locations, and anything else. </p>
<p>This approval impacts your ability to access the system and the extent to which you can do so.</p>
<h2 id="heading-what-is-cross-origin-resource-sharing-cors">What is Cross-Origin Resource Sharing (CORS)?</h2>
<blockquote>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a> is an HTTP header-based system that allows a server to specify any other origins (domain, scheme, or port) from which a browser should enable resources to be loaded other than its own. </p>
</blockquote>
<p>CORS also uses a system in which browsers send a "preflight" request to the server hosting the cross-origin help to ensure that it will allow the actual request.</p>
<p>We will be using the JSON web token standard to represent claims between two parties</p>
<h2 id="heading-what-are-json-web-tokens-jwt">What are JSON Web Tokens (JWT)?</h2>
<blockquote>
<p>JSON Web Tokens (JWT) are an open industry standard defined by RFC 7519 used to represent claims between two parties. <a target="_blank" href="https://jwt.io/introduction">jwt.io</a> </p>
</blockquote>
<p>You can use <a target="_blank" href="https://jwt.io">jwt.io</a> to decode, verify, and create JWTs, for example.</p>
<p>JWT defines a concise and self-contained way of exchanging information between two parties as a JSON object. You can review and trust this information because it is signed. </p>
<p>JWTs can be signed with a secret (using the HMAC algorithm) or a public/private key pair from RSA or ECDSA. We'll see some examples of how to use them in a bit.</p>
<p>Let's get started.</p>
<h2 id="heading-how-to-use-a-token-for-authentication-in-nodejs-development">How to Use a Token for Authentication in Node.js Development</h2>
<p>To get started, first we'll need to set up our project.</p>
<p>Navigate to a directory of your choice on your machine and open it in the terminal to launch Visual Studio Code.</p>
<p>Then execute:</p>
<pre><code class="lang-bash">code.
</code></pre>
<blockquote>
<p><strong>Note</strong>: If you don't have Visual Studio Code installed on your computer, <code>code .</code>  won't work. Just make sure you have it installed before trying this command.</p>
</blockquote>
<h3 id="heading-how-to-create-a-directory-and-set-it-up-with-npm">How to Create a Directory and Set it Up with <code>npm</code></h3>
<p>Create a directory and initialize <code>npm</code> by typing the following command:</p>
<ul>
<li>In Windows power shell:</li>
</ul>
<pre><code class="lang-bash">mkdir cors-auth-project

<span class="hljs-built_in">cd</span> cors-auth-project

npm init -y
</code></pre>
<ul>
<li>In Linux:</li>
</ul>
<pre><code class="lang-bash">mkdir cors-auth-project

<span class="hljs-built_in">cd</span> cors-auth-project

npm init -y
</code></pre>
<h3 id="heading-how-to-create-files-and-directories">How to Create Files and Directories</h3>
<p>In the previous step, we initialized npm with the command <code>npm init -y</code>, which automatically created a package.json file.</p>
<p>We will create the <code>model</code>, <code>middleware</code>, and <code>config</code> directories and their files, for example, <code>user.js</code>, <code>auth.js</code>, <code>database.js</code> using the commands below.</p>
<pre><code class="lang-bash">mkdir model middleware config

touch config/database.js middleware/auth.js model/user.js
</code></pre>
<p>We can now create the <code>index.js</code> and <code>app.js</code> files in the root directory of our project with this command:</p>
<pre><code class="lang-bash">touch app.js index.js
</code></pre>
<p>This will give us a folder structure like the one you see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-19.43.15.png" alt="folder structure" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-install-dependencies">How to Install Dependencies</h3>
<p>We'll install several dependencies like <code>mongoose</code>, <code>jsonwebtoken</code>, <code>express</code>, <code>dotenv</code>, <code>bcryptjs</code>, <code>cors</code> and development dependencies like <code>nodemon</code> to restart the server as we make changes automatically.</p>
<p>Because I'll be using MongoDB in this project, we'll install Mongoose, and the user credentials will be checked against what we have in our database. As a result, the entire authentication process isn't limited to the database we'll use in this tutorial.</p>
<pre><code class="lang-bash">npm install  cors mongoose express jsonwebtoken dotenv bcryptjs 

npm install nodemon -D
</code></pre>
<h3 id="heading-how-to-create-a-nodejs-server-and-connect-your-database">How to Create a Node.js Server and Connect your Database</h3>
<p>Now, add the following snippets to your <code>app.js</code>, <code>index.js</code>, <code>database.js</code>, and <code>.env</code> files in that order to establish our Node.js server and connect our database.</p>
<p>In our <code>database.js.</code>:</p>
<p><code>config/database.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> { MONGO_URI } = process.env;

<span class="hljs-built_in">exports</span>.connect = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Connecting to the database</span>
  mongoose
    .connect(MONGO_URI, {
      <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useCreateIndex</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">useFindAndModify</span>: <span class="hljs-literal">false</span>,
    })
    .then(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Successfully connected to database"</span>);
    })
    .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"database connection failed. exiting now..."</span>);
      <span class="hljs-built_in">console</span>.error(error);
      process.exit(<span class="hljs-number">1</span>);
    });
};
</code></pre>
<p>In our <code>app.js</code>:</p>
<p><code>auth-cors-project/app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
<span class="hljs-built_in">require</span>(<span class="hljs-string">"./config/database"</span>).connect();
<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());

<span class="hljs-comment">// Logic goes here</span>

<span class="hljs-built_in">module</span>.exports = app;
</code></pre>
<p>In our <code>index.js</code>:</p>
<p><code>auth-cors-project/index.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">"http"</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./app"</span>);
<span class="hljs-keyword">const</span> server = http.createServer(app);

<span class="hljs-keyword">const</span> { API_PORT } = process.env;
<span class="hljs-keyword">const</span> port = process.env.PORT || API_PORT;

<span class="hljs-comment">// server listening </span>
server.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Our file, as you can see, requires various environment variables. If you haven't already, create a new <code>.env</code> file and add your variables before running the application.</p>
<p>In our <code>.env.</code>:</p>
<pre><code class="lang-javascript">API_PORT=<span class="hljs-number">4001</span>

MONGO_URI= <span class="hljs-comment">// Your database URI</span>
</code></pre>
<p>Edit the scripts object in our <code>package.json</code> to look like the one below to start our server.</p>
<pre><code class="lang-javascript"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>,
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  }
</code></pre>
<p>We successfully inserted the above snippet into the files <code>app.js</code>, <code>index.js</code>, and <code>database.js</code>. So, we started by creating our Node.js server in <code>index.js</code> and then imported the <code>app.js</code> file, which already had routes configured.</p>
<p>Then, in database.js, we used Mongoose to build a database connection.</p>
<p><code>npm run dev</code> is the command to start our application.</p>
<p>As long as they haven't crashed, both the server and the database should be up and running.</p>
<h3 id="heading-how-to-create-a-user-model-and-route">How to Create a User Model and Route</h3>
<p>After registering for the first time, we'll establish our schema for the user details. Then, when logging in, we'll check them against the remembered credentials.</p>
<p>In the model folder, add the following snippet to <code>user.js</code>:</p>
<p><code>model/user.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">first_name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">null</span> },
  <span class="hljs-attr">last_name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">null</span> },
  <span class="hljs-attr">email</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-attr">password</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span> },
  <span class="hljs-attr">token</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span> },
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"user"</span>, userSchema);
</code></pre>
<p>Now let's create the routes for <code>register</code> and <code>login</code>, respectively.</p>
<p>In <code>app.js</code> in the root directory, add the following snippet for the registration and login.</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// importing user context</span>
<span class="hljs-keyword">const</span> User = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./model/user"</span>);

<span class="hljs-comment">// Register</span>
app.post(<span class="hljs-string">"/register"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">// our register logic goes here...</span>
});

<span class="hljs-comment">// Login</span>
app.post(<span class="hljs-string">"/login"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
<span class="hljs-comment">// our login logic goes here</span>
});
</code></pre>
<h3 id="heading-how-to-implement-register-and-login-functionality">How to Implement Register and Login Functionality</h3>
<p>We'll implement these two routes in our application. Before storing the credentials in our database, we'll use JWT to sign them and <code>bycrypt</code> to encrypt them.</p>
<p>We will: </p>
<ul>
<li>Get user input from the <code>/register</code> route.</li>
<li>Verify the user's input.</li>
<li>Check to see if the user has already been created.</li>
<li>Protect the user's password by encrypting it.</li>
<li>Make a user account in our database.</li>
<li>Finally, construct a JWT token that is signed.</li>
</ul>
<p>Modify the <code>/register</code> route structure we created earlier to look as shown below:</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

app.post(<span class="hljs-string">"/register"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-comment">// Our register logic starts here</span>
   <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Get user input</span>
    <span class="hljs-keyword">const</span> { firstName, lastName, email, password } = req.body;

    <span class="hljs-comment">// Validate user input</span>
    <span class="hljs-keyword">if</span> (!(email &amp;&amp; password &amp;&amp; firstName &amp;&amp; lastName)) {
      res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"All input is required"</span>);
    }

    <span class="hljs-comment">// check if user already exist</span>
    <span class="hljs-comment">// Validate if user exist in our database</span>
    <span class="hljs-keyword">const</span> oldUser = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (oldUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">409</span>).send(<span class="hljs-string">"User Already Exist. Please Login"</span>);
    }

    <span class="hljs-comment">//Encrypt user password</span>
    encryptedUserPassword = <span class="hljs-keyword">await</span> bcrypt.hash(password, <span class="hljs-number">10</span>);

    <span class="hljs-comment">// Create user in our database</span>
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.create({
      <span class="hljs-attr">first_name</span>: firstName,
      <span class="hljs-attr">last_name</span>: lastName,
      <span class="hljs-attr">email</span>: email.toLowerCase(), <span class="hljs-comment">// sanitize</span>
      <span class="hljs-attr">password</span>: encryptedUserPassword,
    });

    <span class="hljs-comment">// Create token</span>
    <span class="hljs-keyword">const</span> token = jwt.sign(
      { <span class="hljs-attr">user_id</span>: user._id, email },
      process.env.TOKEN_KEY,
      {
        <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"5h"</span>,
      }
    );
    <span class="hljs-comment">// save user token</span>
    user.token = token;

    <span class="hljs-comment">// return new user</span>
    res.status(<span class="hljs-number">201</span>).json(user);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err);
  }
  <span class="hljs-comment">// Our register logic ends here</span>
});

<span class="hljs-comment">// ...</span>
</code></pre>
<blockquote>
<p><strong>Note:</strong> Update your <code>.env</code> file with a <code>TOKEN_KEY</code>, which can be a random string.</p>
</blockquote>
<p>Using Postman to test the endpoint, we'll get the response shown below after successful registration.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-22.57.16.png" alt="user registration" width="600" height="400" loading="lazy"></p>
<p>We will: </p>
<ul>
<li>Get user input for the <code>/login</code> route.</li>
<li>Verify the user's input.</li>
<li>Check to see if the user is genuine.</li>
<li>Compare the user's password to the one we saved earlier in our database.</li>
<li>Finally, construct a JWT token that is signed.</li>
</ul>
<p>Make the <code>/login</code> route structure that we defined earlier look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ...</span>

app.post(<span class="hljs-string">"/login"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {

  <span class="hljs-comment">// Our login logic starts here</span>
   <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Get user input</span>
    <span class="hljs-keyword">const</span> { email, password } = req.body;

    <span class="hljs-comment">// Validate user input</span>
    <span class="hljs-keyword">if</span> (!(email &amp;&amp; password)) {
      res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"All input is required"</span>);
    }
    <span class="hljs-comment">// Validate if user exist in our database</span>
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });

    <span class="hljs-keyword">if</span> (user &amp;&amp; (<span class="hljs-keyword">await</span> bcrypt.compare(password, user.password))) {
      <span class="hljs-comment">// Create token</span>
      <span class="hljs-keyword">const</span> token = jwt.sign(
        { <span class="hljs-attr">user_id</span>: user._id, email },
        process.env.TOKEN_KEY,
        {
          <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"5h"</span>,
        }
      );

      <span class="hljs-comment">// save user token</span>
      user.token = token;

      <span class="hljs-comment">// user</span>
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json(user);
    }
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"Invalid Credentials"</span>);

  <span class="hljs-comment">// Our login logic ends here</span>
});

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Using Postman to test, we'll get the response shown below after a successful login.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.00.45.png" alt="user login" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-middleware-for-authentication">How to Create Middleware for Authentication</h3>
<p>We can now create and login a user successfully. Now, we'll establish a route that requires a user token in the header, which will be the JWT token we created before.</p>
<p>Add the following snippet inside <code>auth.js</code>:</p>
<p><code>middleware/auth.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"jsonwebtoken"</span>);

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

<span class="hljs-keyword">const</span> verifyToken = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> token =
    req.body.token || req.query.token || req.headers[<span class="hljs-string">"x-access-token"</span>];

  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">403</span>).send(<span class="hljs-string">"A token is required for authentication"</span>);
  }
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> decoded = jwt.verify(token, config.TOKEN_KEY);
    req.user = decoded;
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).send(<span class="hljs-string">"Invalid Token"</span>);
  }
  <span class="hljs-keyword">return</span> next();
};

<span class="hljs-built_in">module</span>.exports = verifyToken;
</code></pre>
<p>To test the middleware, create the <code>/welcome</code> route and edit app.js with the following code:</p>
<p><code>app.js</code></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> auth = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./middleware/auth"</span>);

app.post(<span class="hljs-string">"/welcome"</span>, auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌"</span>);
});
</code></pre>
<p>When we try to access the /welcome route we just built without sending a token in the header with the x-access-token key, we get the following response:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-2021-06-26-at-23.09.13.png" alt="failed response" width="600" height="400" loading="lazy"></p>
<p>We can now re-test by adding a token in the header with the key x-access-token.</p>
<p>This is the response you'll get:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/success-response.png" alt="success response" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-implement-cross-origin-resource-sharing-cors">How to Implement Cross-Origin Resource Sharing (CORS)</h2>
<p><a target="_blank" href="https://www.npmjs.com/package/cors">CORS</a> is a Node.js package that provides a Connect/Express middleware that you can. use to enable CORS with a variety of parameters.</p>
<ol>
<li>It's easy to use (Enable All CORS Requests)</li>
</ol>
<p>Adding the following snippet to <code>app.js</code> allows us to add CORS to our application and enable all CORS requests.</p>
<pre><code><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>) <span class="hljs-comment">//Newly added</span>
<span class="hljs-keyword">const</span> app = express();

app.use(cors()) <span class="hljs-comment">// Newly added</span>


app.use(express.json({ <span class="hljs-attr">limit</span>: <span class="hljs-string">"50mb"</span> }));

<span class="hljs-comment">// ...</span>
</code></pre><ol start="2">
<li>You can enable CORS for a single route</li>
</ol>
<p>Using the <code>/welcome</code> route as an example, you can activate CORS for a single route in your application by adding the following snippet in <code>app.js.</code>:</p>
<pre><code>app.get(<span class="hljs-string">'/welcome'</span>, cors(), auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌 "</span>);
});
</code></pre><ol start="3">
<li>How to configure CORS</li>
</ol>
<p>We can set options in the CORS package by adding parameters to configure it, as shown below:</p>
<pre><code><span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> corsOptions = {
  <span class="hljs-attr">origin</span>: <span class="hljs-string">'http://example.com'</span>,
  <span class="hljs-attr">optionsSuccessStatus</span>: <span class="hljs-number">200</span> <span class="hljs-comment">// for some legacy browsers</span>
}

app.get(<span class="hljs-string">'/welcome'</span>, cors(corsOptions), auth, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"Welcome to FreeCodeCamp 🙌 "</span>);
});

<span class="hljs-comment">// ...</span>
</code></pre><p>You can check out <a target="_blank" href="https://www.npmjs.com/package/cors">NPM CORS PACKAGE</a> to read more about Cross-Origin Resource Sharing.</p>
<p>You can <a target="_blank" href="https://github.com/Olanetsoft/auth-cors-demo">click here</a> to check out the complete code on GitHub.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned about JWT, authentication, authorization, and CORS. We also learned how to create an API in Node.js that uses a JWT token for authentication.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ API Cheat Sheet – What is an API, How it Works, and How to Choose the Right API Testing Tools ]]>
                </title>
                <description>
                    <![CDATA[ Building an API is fun, right? In this article, I will explain what APIs are, why you need them, and we'll dive into API specifications, documentation, and more. Programming is made simpler by using APIs to abstract away certain implementations, and ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-an-api-and-how-to-test-it/</link>
                <guid isPermaLink="false">66b905dde8c4e204927a90ec</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Sat, 06 Feb 2021 02:15:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/02/api.PNG" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building an API is fun, right?</p>
<p>In this article, I will explain what APIs are, why you need them, and we'll dive into API specifications, documentation, and more.</p>
<p>Programming is made simpler by using APIs to abstract away certain implementations, and expose actions or endpoints to developers who need to consume the endpoints when building applications.</p>
<p>But APIs can get pretty complex depending on the application's code base and use cases. This means that testing your API endpoints might be a tricky process after developing them. Fortunately, there are amazing tools out there that I will share to help you test your APIs efficiently.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li>Introduction to APIs</li>
<li>Types of APIs</li>
<li>Why do we need APIs?</li>
<li>API Specifications</li>
<li>API Testing tools</li>
<li>API Documentation</li>
<li>Conclusion</li>
</ul>
<h2 id="heading-what-is-an-api">What is an API?</h2>
<p>An API (Application Programming Interface) serves as a middleware that lets you channel data between software products.</p>
<p>You can use it to define requests that have been made, handle business logic, the and manage data formats that should be used and the conventions to adhere to when building software products. </p>
<h2 id="heading-types-of-apis">Types of APIs</h2>
<p>There are three main types of APIs, which are:</p>
<ul>
<li>Private</li>
<li>Public/Partner</li>
<li>External</li>
</ul>
<h3 id="heading-private-apis">Private APIs</h3>
<p>These are APIs builts solely for use within an organization. They are classified as an in-house application for employees to automate business processes and delivery.</p>
<h3 id="heading-publicpartner-apis">Public/Partner APIs</h3>
<p>These are APIs that are openly promoted but available for known developers or business partners. These usually represent software integrations between organizations. </p>
<h3 id="heading-external-apis">External APIs</h3>
<p>These are completely external APIs, as the name implies, which are available to any third-party developer and are mostly designed or built for end-users/customers.</p>
<h2 id="heading-why-do-we-need-apis">Why do we need APIs?</h2>
<p>APIs make it easier to access to a variety of resources. They also allow cross-platform communication which solves certain business logic.</p>
<h3 id="heading-apis-are-efficient">APIs are efficient</h3>
<p>APIs hosted and created by a third-party application can significantly reduce the amount of work within your organization. This, in turn, will speed up the development process of an application. </p>
<p>Companies outsource some part of the business process for a fragment of the cost to build the same application within the organization.</p>
<h3 id="heading-apis-make-things-simpler">APIs make things simpler</h3>
<p>APIs simplify complex logic by tackling different business logic in chunks. They also provide user-friendly endpoints specific to certain use cases. </p>
<p>An API can provide data you need without requiring extra research or manipulation which speeds up the development process.</p>
<h2 id="heading-api-specifications">API Specifications</h2>
<p>There are a few different types of API specifications, which we'll discuss now.</p>
<h3 id="heading-representational-state-transfer-rest">Representational State Transfer (REST)</h3>
<p>Representational State Transfer (REST) is a style of architecture that provides standards on the web between computer systems which makes communication flow easier within applications. </p>
<p>REST APIs are stateless and can be used for separation of concerns between the client and server.</p>
<h3 id="heading-service-object-access-protocol-soap">Service Object Access Protocol (SOAP)</h3>
<p>According to the definition by <a target="_blank" href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wusp/5daaa9d9-26aa-42fc-a431-c011166dc58f">Microsoft</a>, SOAP is a lightweight protocol for exchanging structured information in a decentralized, distributed environment. </p>
<p>This contains rules guiding requests and responses sent from web applications using XML between systems through Hypertext Transfer Protocol (HTTP). </p>
<h3 id="heading-graphql">GraphQL</h3>
<p>GraphQL is a query language for APIs. It provides an absolute and simplified description of the data in APIs which gives you the power to get the exact data you need. This makes it easier to evolve APIs over time and also enables powerful developer tools.</p>
<h2 id="heading-api-testing-tools">API Testing Tools</h2>
<p>Testing your API endpoints might be challenging after developing them, but there are some super helpful tools I'll share here that'll help you test your APIs efficiently.</p>
<h3 id="heading-postwomanhoppscotchhttpshoppscotchio"><a target="_blank" href="https://hoppscotch.io/">Postwoman/Hoppscotch</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610838514220/wgOkw8vQ3.png" alt="image.png" width="3827" height="1941" loading="lazy"></p>
<p>A free, fast, and beautiful API request builder with an online testing environment, support for multiple platforms and multiple devices, and many more features.</p>
<h3 id="heading-rest-assuredhttprest-assuredio"><a target="_blank" href="http://rest-assured.io/">REST-assured</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610837510019/Ov6MVxfni.png" alt="image.png" width="3760" height="1918" loading="lazy"></p>
<p>This tool simplifies testing API endpoints in Java – yes JAVA. It tests and validates responses, making it seamless for Java devs to test APIs.</p>
<h3 id="heading-pawhttpspawcloud"><a target="_blank" href="https://paw.cloud/">Paw</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610837773386/2R87zfCwx.png" alt="image.png" width="3802" height="1915" loading="lazy"></p>
<p>Paw is a full-featured HTTP client that lets you test and describe the APIs you build or consume. It has a beautiful native macOS interface to compose requests, inspect server responses, generate client code, and export API definitions.</p>
<h3 id="heading-postmanhttpswwwpostmancom"><a target="_blank" href="https://www.postman.com/">Postman</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610837360130/6c-I1EOBsG.png" alt="image.png" width="3789" height="1920" loading="lazy">
Postman is a collaboration platform for API development. The awesome thing about this tool is that it simplifies each step of building an API and it also makes collaboration seamless for building faster APIs.</p>
<h3 id="heading-soapuihttpswwwsoapuiorgdownloadssoapui"><a target="_blank" href="https://www.soapui.org/downloads/soapui/">SoapUI</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610838275333/aNen9DiyH.png" alt="image.png" width="3759" height="1918" loading="lazy">
This is also a testing tool that can help to make testing API endpoints seamless.</p>
<h3 id="heading-firecamphttpsfirecampio"><a target="_blank" href="https://firecamp.io/">Firecamp</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610838609975/NMgS4VRQP.png" alt="image.png" width="3783" height="1923" loading="lazy">
This is a tool with friendly UI and can be used to test any stack. It doesn't matter which tech stack you use, ranging from REST API, WebSockets, GraphQL, and so on in software engineering.</p>
<h3 id="heading-karatehttpsintuitgithubiokarate"><a target="_blank" href="https://intuit.github.io/karate/">Karate</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610838910786/HV8JjrBvP.png" alt="image.png" width="3749" height="1893" loading="lazy">
Karate is an open-source tool for operations like API test-automation, performance-testing, UI automation into a single, and so on.</p>
<h3 id="heading-api-fortresshttpsapifortresscom"><a target="_blank" href="https://apifortress.com/">API Fortress</a></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610839080287/6jRcD2BHL.png" alt="image.png" width="3782" height="1896" loading="lazy">
This is a great tool for testing REST, SOAP, GraphQL, Web Services, and Microservices. It also helps you automate tests as part of a CI pipeline, monitor internal APIs continuously, and so on.</p>
<h2 id="heading-api-documentation">API Documentation</h2>
<p>API Documentation is one of the most important things to consider after developing and testing your APIs. It simplifies the process of understanding what each endpoint does as well as how their requests and responses work.</p>
<p>Imagine you build several endpoints for user authentication. If you aren't available, but one of the frontend developers on your team wants to consume it, that could be a proble. If there is no guide or instructions explaining what each API does and there are no sample requests and responses, it can really slow down the development process.</p>
<p>Here are some tools you can use for APIs documentation so you don't have these issues:</p>
<ul>
<li><a target="_blank" href="https://swagger.io/">Swagger</a></li>
<li><a target="_blank" href="https://apidocjs.com/">apiDoc</a></li>
<li><a target="_blank" href="https://www.postman.com/api-documentation-tool/">Postman</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building and testing your API should be fun, shouldn't it? I hope you found this resource useful and it helps you have fun with your APIs.</p>
<p>You can reach out to me on <a target="_blank" href="https://twitter.com/olanetsoft">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Deploy a Front End Application with Netlify ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this article, I'm going to discuss how to deploy an application you've built. The application deployment process might seem complicated, and this might prevent some developers from deploying their applications after they've developed ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-deploy-your-front-end-app/</link>
                <guid isPermaLink="false">66b905d7472b70138041a587</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Idris Olubisi ]]>
                </dc:creator>
                <pubDate>Sat, 09 Jan 2021 00:23:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/Turquoise-Confetti-Birthday-Greetings-Facebook-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this article, I'm going to discuss how to deploy an application you've built.</p>
<p>The application deployment process might seem complicated, and this might prevent some developers from deploying their applications after they've developed them. </p>
<p>So here, I will be taking you through a seamless process to spin up your application which can then be accessed anywhere in the world via a URL.</p>
<h3 id="heading-table-of-contents">Table of contents</h3>
<ul>
<li>Why do you need to deploy your frontend applications?</li>
<li>What is Netlify?</li>
<li>What you can do with Netlify</li>
<li>How to deploy your site</li>
<li>Resources</li>
</ul>
<h2 id="heading-why-do-you-need-to-deploy-your-frontend-applications">Why do you need to deploy your frontend applications?</h2>
<p>There are numerous advantages to deploying your applications. Of course, you don't want your beautiful application to sit on your localhost forever. </p>
<p>Deploying your application makes it easier to share your project, side-gig, or startup with potential investors or future employers. If they can see those projects, it helps them gauge your skills. It also lets you show off your progress to the world.</p>
<p>In this article, we will be using the amazing [Netlify](https://www.netlify.com 'Netlify Homepage') platform to deploy our application.</p>
<p>That name sounds familiar, right? But if you haven't used it to deploy a web application yet, trust me I know how you feel. </p>
<p>I will take you through the steps to get your site deployed to <a target="_blank" href="https://www.netlify.com">Netlify</a> in less than 4 minutes. We'll also see some other functionalities that can be done with Netlify out of the box.</p>
<h2 id="heading-what-is-netlify">What is Netlify?</h2>
<p><a target="_blank" href="https://netlify.com/">Netlify</a> is a platform that lets developers automate modern web projects, and it's a place where you can deploy your application without worrying about frustrating configurations. </p>
<p>You can also integrate cool features and dynamic functionality like serverless functions and form handling on Netlify. Sounds good, right?</p>
<h2 id="heading-netlify-features">Netlify Features</h2>
<h3 id="heading-configure-builds">Configure builds</h3>
<p>Netlify helps you run the build command each time you push an update to your repository. </p>
<p>There are additional settings that you can configure like auto-deploy along with other useful deployment settings.</p>
<h3 id="heading-site-deploys-atomic-deployshttpsdocsnetlifycomsite-deploysoverview">Site deploys <a target="_blank" href="https://docs.netlify.com/site-deploys/overview/">(Atomic deploys)</a></h3>
<p>One of the awesome features Netlify has is site deployment. It ensures that your site is deployed and always consistent. </p>
<p>You can also enable deploy notifications, run a test while Netlify compares the new deploy with the existing one, and then update only the files that have been changed.</p>
<h3 id="heading-monitor-sites-netlify-analyticshttpsdocsnetlifycommonitor-sitesanalytics">Monitor sites <a target="_blank" href="https://docs.netlify.com/monitor-sites/analytics/">(Netlify Analytics)</a></h3>
<p>Monitoring your site might become difficult if you don't have proper infrastructure in place. </p>
<p>You can easily monitor your site'sactivities on this platform where you can track each log on the team's build usage.</p>
<h4 id="heading-domains-amp-https-register-new-domainshttpsdocsnetlifycomdomains-httpsnetlify-dnsdomain-registration">Domains &amp; HTTPS <a target="_blank" href="https://docs.netlify.com/domains-https/netlify-dns/domain-registration">(Register new domains)</a></h4>
<p>In simple terms, a domain is the URL anyone types into the browser to visit your site. You can assign a custom domain if you have already purchased one or secure a domain from Netlify. </p>
<p>Either way, the domain name system management is handled by Netlify. They also provide free automatic HTTPS on all sites. Cool right?</p>
<h4 id="heading-routing-learn-about-routinghttpsdocsnetlifycomroutingredirects">Routing <a target="_blank" href="https://docs.netlify.com/routing/redirects/">(Learn about routing)</a></h4>
<p>Routing, Redirects, proxies, and so on all become much easier when your site is deployed on Netlify.</p>
<h3 id="heading-visitor-access">Visitor access</h3>
<p>Here's another cool feature I enjoy: whenever you need to add someone to the team, you can set up role-based access controls that allow the Admin/Senior developer to take control and give access to individuals on the team to avoid escalations.</p>
<h3 id="heading-forms-netlify-formshttpsdocsnetlifycomformssetup">Forms <a target="_blank" href="https://docs.netlify.com/forms/setup/">(Netlify Forms)</a></h3>
<p>When you need to collect data from users on a site deployed on Netlify, you can do so using Netlify forms. This doesn't add API calls or extra JavaScript on your site, either.</p>
<p>Build bots handle form submission by parsing your HTML files directly at deploy time. You can also configure the receiver, group, and notifications.</p>
<h3 id="heading-functions-deploy-serverless-functionshttpsdocsnetlifycomfunctionsoverview">Functions <a target="_blank" href="https://docs.netlify.com/functions/overview/">(Deploy serverless functions)</a></h3>
<p>Serverless functions can be referred to as single-purpose, programmatic functions that are hosted on managed infrastructure.</p>
<p>Netlify lets you deploy serverless Lambda functions with management handled directly within Netlify, while they are built and deployed with the rest of your sites.</p>
<h3 id="heading-the-netlify-cli-netlify-command-line-interfacehttpsdocsnetlifycomcliget-started">The Netlify CLI <a target="_blank" href="https://docs.netlify.com/cli/get-started">(Netlify command-line interface)</a></h3>
<p>You might be wondering if all activities are carried out on the Netlify UI alone - well, no they're not. </p>
<p>There is another great feature that allows developers to deploy sites or do some configuration right from their terminal. The Netlify CLI can be used to run a local development server that can be shared, including plugins.</p>
<h3 id="heading-the-netlify-api-netlify-apihttpsdocsnetlifycomapiget-startedauthentication">The Netlify API <a target="_blank" href="https://docs.netlify.com/api/get-started/#authentication">(Netlify API)</a></h3>
<p>Netlify's API can be used to handle the deployment of sites, script injections, and more. It uses JSON for serialization, which conforms to the REST standard.</p>
<h3 id="heading-accounts-amp-billing">Accounts &amp; billing</h3>
<p>Learn about <a target="_blank" href="https://docs.netlify.com/accounts-and-billing/team-management/manage-team-members">managing team members</a> and how to transfer sites between teams.</p>
<blockquote>
<p>I hope you can now see how powerful Netlify is. Sut seeing sometimes can be deceiving, so let's try it out on our own.</p>
</blockquote>
<p>As you can tell from the title of this article, I will only be showing you how to deploy your site to netlify.com. But to explore other functionalities <a target="_blank" href="https://docs.netlify.com/">click here to read more</a>, practice, and explore.</p>
<h2 id="heading-how-to-deploy-a-site-to-netlify">How to Deploy a Site to Netlify</h2>
<h3 id="heading-step-one">Step One</h3>
<p>Login or signup on netlify.com if you are a new user. It's free :)</p>
<h3 id="heading-step-two">Step Two</h3>
<p>As shown below, all you need is to select a site from Git by clicking on the button with the name “New site from Git”.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119982/netlify%20deploy%20post/Screenshot.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-three">Step Three</h3>
<p>You will see the interface below where you can choose the Git provider where your site source code is hosted.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/select_git.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-four">Step Four</h3>
<p>Choose the repository you want to link to your site on Netlify.</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/select_repo.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-five">Step Five</h3>
<p>We are almost there :)</p>
<p>This section allows you to get more control over how Netlify builds and deploys your site with the settings option shown below:</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119981/netlify%20deploy%20post/select_to_deploy_site.jpg" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-six">Step Six</h3>
<p>Wait, Netlify is getting things ready for you. :)</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/site_deploy_in_pgrogress.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-seven">Step Seven</h3>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/site.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>Congratulation Your site is Live!</p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119980/netlify%20deploy%20post/Screenshot1.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>Click on the generated URL with the .netlify.com extension below the header that states “Deploys for”.</p>
<p><strong>Lastly: You can also set up a new domain or change the generated one to something nice by clicking on the “…” that embeds “Edit site name” but it will end with .netlify.com. <a target="_blank" href="https://docs.netlify.com/domains-https/custom-domains/">Click here to read more</a></strong></p>
<p><img src="https://res.cloudinary.com/olanetsoft/image/upload/v1608119981/netlify%20deploy%20post/domain_setup.png" alt="Netlify" width="600" height="400" loading="lazy"></p>
<p>I hope you have found this guide useful :)</p>
<p>NOTE: the Netlify URL extension is now netlify.app. All netlify.com URLs will now be redirected to netlify.app.</p>
<p><strong>Please don't forget to check out my other articles, it gives me joy :) and the vibes to write more stuff.</strong></p>
<p>You can also reach out to me on <a target="_blank" href="https://twitter.com/olanetsoft">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
