<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Software Ledger by Saiful Alam]]></title><description><![CDATA[Explore the dynamic world of web development with insights into Laravel, PHP, ReactJS, and JavaScript. Dive into expert tips, tutorials, and the latest trends shaping these powerful technologies.]]></description><link>https://blog.msar.me</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 02:31:21 GMT</lastBuildDate><atom:link href="https://blog.msar.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Caddy — A powerful web server!]]></title><description><![CDATA[1. Introduction
Caddy is an open-source web server written in Go that is designed to make running and deploying web applications simple. Unlike older servers such as Apache or Nginx, Caddy focuses on removing friction — especially around configuratio...]]></description><link>https://blog.msar.me/caddy-a-powerful-web-server</link><guid isPermaLink="true">https://blog.msar.me/caddy-a-powerful-web-server</guid><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Wed, 17 Dec 2025 17:40:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765993566909/9ac6b0e1-274e-43cb-8b88-657a7aa0b055.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-1-introduction"><strong>1. Introduction</strong></h2>
<p>Caddy is an open-source web server written in Go that is designed to make running and deploying web applications simple. Unlike older servers such as Apache or Nginx, Caddy focuses on removing friction — especially around configuration and HTTPS management — so you can spend more time building and less time babysitting infrastructure.</p>
<p>One of Caddy’s biggest conveniences is automatic HTTPS. With sensible defaults and an easy-to-read Caddyfile, you don’t need to learn a complex configuration language or wrestle with TLS certificates. Caddy also includes built-in support for HTTP/3, which helps ensure fast, modern performance today and better compatibility for the future.</p>
<p>Caddy runs with zero runtime dependencies, making it lightweight and straightforward to install. It’s also capable: you can use it as a reverse proxy with load balancing, caching, circuit breaking, and health checks. If you need additional functionality, Caddy supports plugins to extend its capabilities.</p>
<p>These features make Caddy a reliable option for both hobby projects and enterprise deployments. Whether you’re just getting started or you’re an experienced developer, Caddy aims to make server management painless so you can focus on your application.</p>
<p>In this article, we’ll walk through key Caddy features — serving static files, proxying requests to backend apps, automatic HTTPS, and how it can integrate with observability tools for logging and uptime monitoring.</p>
<hr />
<h2 id="heading-2-prerequisites"><strong>2. Prerequisites</strong></h2>
<p>Before you begin, make sure you have a few basic tools and settings in place so the examples run smoothly:</p>
<ul>
<li><p>Comfortable using the command line — you’ll be running a few terminal commands.</p>
</li>
<li><p>Docker and Docker Compose (recent versions) installed on your machine so you can build and run the example containers.</p>
</li>
<li><p>Git installed so you can clone the example repositories.</p>
</li>
<li><p>(Optional) A domain name if you want to follow the HTTPS examples end-to-end.</p>
</li>
</ul>
<p>If any of these are missing, you can install them quickly with your platform’s package manager or Docker’s official installer; the domain is only required when you want to test the automatic HTTPS flow.</p>
<hr />
<h2 id="heading-3-caddys-automatic-https-amp-ssl-features"><strong>3. Caddy’s Automatic HTTPS &amp; SSL Features</strong></h2>
<p>One of Caddy’s most compelling value propositions is how it completely rethinks HTTPS. Traditionally, TLS setup has been operationally heavy — manual certificate issuance, cron-based renewals, and brittle configurations. Caddy removes that entire layer of complexity and makes HTTPS the default, not an afterthought.</p>
<h3 id="heading-31-how-automatic-https-works"><strong>3.1 How Automatic HTTPS Works</strong></h3>
<p>When you configure Caddy with a valid domain name, it automatically handles HTTPS for you. There is no need to generate certificates manually, install Certbot, or set up renewal scripts.</p>
<p><strong>Basic workflow</strong></p>
<pre><code class="lang-plaintext">Caddy starts
   ↓
Detects domain from config
   ↓
Requests SSL certificate
   ↓
Verifies domain ownership
   ↓
Enables HTTPS
</code></pre>
<p>Caddy communicates directly with a Certificate Authority such as Let’s Encrypt, configures secure TLS settings, and stores the certificate locally. Renewal is also handled automatically before the certificate expires.</p>
<p><strong>Simple example</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">example</span>.com {
    <span class="hljs-attribute">reverse_proxy</span> localhost:<span class="hljs-number">3000</span>
}
</code></pre>
<p>That’s enough. Once Caddy starts, <a target="_blank" href="https://example.com">https://example.com</a> works automatically.</p>
<h3 id="heading-32-wildcard-ssl-certificates"><strong>3.2 Wildcard SSL Certificates</strong></h3>
<p>Wildcard certificates are useful when you need to secure multiple subdomains under a single domain, such as:</p>
<ul>
<li><p><a target="_blank" href="http://app.example.com">app.example.com</a></p>
</li>
<li><p><a target="_blank" href="http://api.example.com">api.example.com</a></p>
</li>
<li><p><a target="_blank" href="http://admin.example.com">admin.example.com</a></p>
</li>
<li><p>or even dynamic, user-generated subdomains</p>
</li>
</ul>
<p>Instead of issuing and managing certificates for each subdomain individually, a wildcard certificate like *.<a target="_blank" href="http://example.com">example.com</a> covers them all. This is especially valuable in multi-tenant systems, SaaS platforms, and environments where subdomains are created dynamically.</p>
<p>To issue a wildcard certificate, Caddy uses the <strong>DNS challenge</strong>. This method proves domain ownership by creating a temporary DNS record rather than serving a file over HTTP. Because of this, you need API access to your DNS provider (such as Cloudflare, Route53, or DigitalOcean).</p>
<h3 id="heading-33-certificate-management-amp-security"><strong>3.3 Certificate Management &amp; Security</strong></h3>
<p>After certificates are issued, Caddy continues managing them in the background.</p>
<h4 id="heading-automatic-renewals"><strong>Automatic renewals</strong></h4>
<p>Caddy monitors certificate expiration dates and renews them automatically. No cron jobs, no restarts, and no manual intervention are required.</p>
<h4 id="heading-handling-failures"><strong>Handling failures</strong></h4>
<p>If a challenge fails due to DNS issues or permission problems, Caddy:</p>
<ul>
<li><p>Logs clear error messages</p>
</li>
<li><p>Retries automatically</p>
</li>
<li><p>Keeps the existing certificate until renewal succeeds</p>
</li>
</ul>
<p>This reduces the risk of unexpected HTTPS downtime.</p>
<hr />
<h2 id="heading-4-setting-up-caddy-for-local-development"><strong>4. Setting Up Caddy for Local Development</strong></h2>
<p>The examples below focus mainly on <strong>macOS and Linux</strong>, for Windows, follow the official <a target="_blank" href="https://caddyserver.com/docs/install">documentation</a>.</p>
<h3 id="heading-41-installing-caddy"><strong>4.1 Installing Caddy</strong></h3>
<p>Installing Caddy is straightforward and doesn’t require complex dependencies.</p>
<h4 id="heading-macos-homebrew"><strong>macOS (Homebrew)</strong></h4>
<pre><code class="lang-bash">brew install caddy
</code></pre>
<h4 id="heading-linux-official-repository"><strong>Linux (official repository)</strong></h4>
<pre><code class="lang-bash">sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf <span class="hljs-string">'https://dl.cloudsmith.io/public/caddy/stable/gpg.key'</span> | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf <span class="hljs-string">'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt'</span> | sudo tee /etc/apt/sources.list.d/caddy-stable.list
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
</code></pre>
<h4 id="heading-windows"><strong>Windows</strong></h4>
<p>Download the binary or installer from the official Caddy website and follow the installer steps.</p>
<h4 id="heading-verifying-the-installation"><strong>Verifying the installation</strong></h4>
<p>After installation, confirm Caddy is available:</p>
<pre><code class="lang-bash">caddy version
</code></pre>
<p>If you see a version number, Caddy is ready to use.</p>
<h3 id="heading-42-running-multiple-local-sites"><strong>4.2 Running Multiple Local Sites</strong></h3>
<p>A common local setup involves working on <strong>multiple projects at the same time</strong>. Caddy handles this cleanly using a single configuration file.</p>
<h4 id="heading-example-local-project-structure"><strong>Example local project structure</strong></h4>
<pre><code class="lang-apache">~/<span class="hljs-attribute">projects</span>/
 ├── <span class="hljs-attribute">blog</span>
 ├── <span class="hljs-attribute">api</span>
 └── <span class="hljs-attribute">dashboard</span>
</code></pre>
<p>Each project can be mapped to its own local domain.</p>
<h4 id="heading-using-custom-test-domains"><strong>Using custom .test domains</strong></h4>
<p>Add entries to your /etc/hosts file:</p>
<pre><code class="lang-apache"><span class="hljs-attribute">127</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> blog.test
<span class="hljs-attribute">127</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> api.test
<span class="hljs-attribute">127</span>.<span class="hljs-number">0</span>.<span class="hljs-number">0</span>.<span class="hljs-number">1</span> dashboard.test
</code></pre>
<p>.test domains are reserved for local use and work well for development.</p>
<h4 id="heading-single-caddyfile-with-multiple-sites"><strong>Single Caddyfile with multiple sites</strong></h4>
<pre><code class="lang-apache"><span class="hljs-attribute">blog</span>.test {
    <span class="hljs-attribute">root</span> * ~/projects/blog
    <span class="hljs-attribute">file_server</span>
}

<span class="hljs-attribute">api</span>.test {
    <span class="hljs-attribute">reverse_proxy</span> localhost:<span class="hljs-number">4000</span>
}

<span class="hljs-attribute">dashboard</span>.test {
    <span class="hljs-attribute">reverse_proxy</span> localhost:<span class="hljs-number">5173</span>
}
</code></pre>
<h3 id="heading-43-local-https"><strong>4.3 Local HTTPS</strong></h3>
<p>Modern applications often rely on HTTPS-only features such as:</p>
<ul>
<li><p>Secure cookies</p>
</li>
<li><p>OAuth callbacks</p>
</li>
<li><p>Service workers</p>
</li>
<li><p>SameSite cookie policies</p>
</li>
</ul>
<p>Caddy makes local HTTPS easy using <strong>internal certificates</strong>.</p>
<h4 id="heading-using-tls-internal"><strong>Using tls internal</strong></h4>
<pre><code class="lang-apache"><span class="hljs-attribute">blog</span>.test {
    <span class="hljs-attribute">root</span> * ~/projects/blog
    <span class="hljs-attribute">file_server</span>
    <span class="hljs-attribute">tls</span> internal
}
</code></pre>
<p>This tells Caddy to:</p>
<ul>
<li><p>Create a local Certificate Authority</p>
</li>
<li><p>Issue trusted certificates for local domains</p>
</li>
<li><p>Manage everything automatically</p>
</li>
</ul>
<p>On first run, Caddy may ask for permission to trust its local CA.</p>
<hr />
<h2 id="heading-5-reusable-snippets-custom-reusable-config-blocks"><strong>5. Reusable Snippets (Custom Reusable Config Blocks)</strong></h2>
<p>As projects grow, Caddyfiles can quickly become repetitive. The same headers, compression rules, or security settings often appear across multiple sites. Caddy solves this problem with <strong>snippets</strong> — small, reusable configuration blocks that help keep your setup clean and consistent.</p>
<h3 id="heading-51-why-snippets-matter"><strong>5.1 Why Snippets Matter</strong></h3>
<p>Snippets allow you to define common configuration once and reuse it everywhere. This is especially useful when working with multiple local projects or managing several environments.</p>
<p>Key benefits:</p>
<ul>
<li><p>Avoid repeating the same configuration across sites</p>
</li>
<li><p>Reduce copy-paste errors</p>
</li>
<li><p>Make updates easier and safer</p>
</li>
<li><p>Keep Caddyfiles readable as setups grow</p>
</li>
</ul>
<p>In short, snippets help you treat your Caddy configuration like real, maintainable code.</p>
<h3 id="heading-52-creating-your-own-snippets"><strong>5.2 Creating Your Own Snippets</strong></h3>
<p>Snippets are defined using parentheses and can contain any valid Caddy directives, here are some snippets example.</p>
<h4 id="heading-example-security-headers-snippet"><strong>Example: security headers snippet</strong></h4>
<pre><code class="lang-bash">(security_headers) {
    header {
        X-Content-Type-Options <span class="hljs-string">"nosniff"</span>
        X-Frame-Options <span class="hljs-string">"DENY"</span>
        Referrer-Policy <span class="hljs-string">"no-referrer"</span>
        Strict-Transport-Security <span class="hljs-string">"max-age=31536000; includeSubDomains"</span>
    }
}
</code></pre>
<p><strong>Snippet for CORS (useful for API development)</strong></p>
<pre><code class="lang-bash">(cors_dev) {
    @cors_preflight method OPTIONS
    handle @cors_preflight {
        header {
            Access-Control-Allow-Origin <span class="hljs-string">"*"</span>
            Access-Control-Allow-Methods <span class="hljs-string">"GET, POST, PUT, PATCH, DELETE, OPTIONS"</span>
            Access-Control-Allow-Headers <span class="hljs-string">"Content-Type, Authorization"</span>
            Access-Control-Max-Age <span class="hljs-string">"3600"</span>
        }
        respond 204
    }
    header {
        Access-Control-Allow-Origin <span class="hljs-string">"*"</span>
        Access-Control-Allow-Credentials <span class="hljs-string">"true"</span>
    }
}
</code></pre>
<p><strong>Proxy with fallback and custom error handling</strong></p>
<pre><code class="lang-bash">
(proxy_with_fallback) {
    reverse_proxy {args[0]} {
        transport http {
            dial_timeout 2s
            response_header_timeout 30s
        }
    }
    handle_errors {
        respond <span class="hljs-string">"Service temporarily unavailable. Please try again later."</span> 503
    }
}
</code></pre>
<h4 id="heading-using-snippets-in-a-site"><strong>Using snippets in a site</strong></h4>
<pre><code class="lang-apache"><span class="hljs-attribute">example</span>.com {
    <span class="hljs-attribute">import</span> security_headers

    <span class="hljs-attribute">import</span> proxy_with_fallback <span class="hljs-number">3000</span>
}
</code></pre>
<h3 id="heading-53-using-snippets-across-local-amp-production-sites"><strong>5.3 Using Snippets Across Local &amp; Production Sites</strong></h3>
<p>A common pattern is to keep all snippets at the <strong>top of the Caddyfile</strong> or move them into a <strong>separate file</strong>:</p>
<p><strong>Example structure</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">caddy</span>/
 ├── <span class="hljs-attribute">Caddyfile</span>
 └── <span class="hljs-attribute">snippets</span>/
     ├── <span class="hljs-attribute">security</span>.caddy
     ├── <span class="hljs-attribute">proxy</span>.caddy
     └── <span class="hljs-attribute">cors</span>.caddy
</code></pre>
<p>Then just add this to your main Caddyfile.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">import</span> snippets/*.caddy

<span class="hljs-attribute">example</span>.com, www.example.com {
    <span class="hljs-attribute">import</span> security_headers
    <span class="hljs-attribute">import</span> cors_dev
}
</code></pre>
<hr />
<h2 id="heading-6-caddyfile-configuration-default-vs-custom-paths"><strong>6. Caddyfile Configuration: Default vs Custom Paths</strong></h2>
<p>As your Caddy setup grows beyond a single site, understanding <strong>where Caddy loads its configuration from</strong> becomes important. Caddy is flexible here — it works out of the box with sensible defaults, but also gives you full control when you need custom paths or structured setups.</p>
<h3 id="heading-61-default-caddyfile-path"><strong>6.1 Default Caddyfile Path</strong></h3>
<p>By default, Caddy looks for a file named <strong>Caddyfile</strong> in a standard system location.</p>
<p>Common default paths:</p>
<ul>
<li><p><strong>Linux:</strong> /etc/caddy/Caddyfile</p>
</li>
<li><p><strong>macOS (Homebrew):</strong> /opt/homebrew/etc/caddy/Caddyfile</p>
</li>
<li><p><strong>Windows:</strong> C:\caddy\Caddyfile (or install directory)</p>
</li>
</ul>
<p>When Caddy is installed as a service, it automatically loads this file on startup.</p>
<h3 id="heading-62-using-a-custom-caddyfile-path"><strong>6.2 Using a Custom Caddyfile Path</strong></h3>
<p>In real projects, especially during development, you often want multiple Caddyfiles — one per project or environment. Caddy supports this cleanly.</p>
<p>Running Caddy with a custom config</p>
<p><code>caddy run --config ./Caddyfile</code></p>
<p>Or explicitly specify the format:</p>
<p><code>caddy run --config ./Caddyfile --adapter caddyfile</code></p>
<p><strong>For development uses</strong></p>
<ul>
<li><p>Keep the Caddyfile inside the project</p>
</li>
<li><p>Easy to version-control</p>
</li>
<li><p>Quick local iteration</p>
</li>
</ul>
<pre><code class="lang-apache"><span class="hljs-attribute">project</span>/
 ├── <span class="hljs-attribute">Caddyfile</span>
 └── <span class="hljs-attribute">src</span>/
</code></pre>
<p><strong>For production uses</strong></p>
<ul>
<li><p>Use the system Caddyfile</p>
</li>
<li><p>Managed by systemd or service manager</p>
</li>
<li><p>Centralized configuration</p>
</li>
</ul>
<p><code>/etc/caddy/Caddyfile</code></p>
<p><strong>Typical workflow</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">Local</span> dev → custom Caddyfile
<span class="hljs-attribute">Staging</span>   → custom path
<span class="hljs-attribute">Production</span> → default system path
</code></pre>
<p>This separation helps avoid accidental config changes in production.</p>
<h3 id="heading-63-structure-tips-for-large-configurations"><strong>6.3 Structure Tips for Large Configurations</strong></h3>
<p>As the number of sites increases, a single large Caddyfile can become hard to manage. Caddy provides simple tools to keep things organized.</p>
<h4 id="heading-split-configs-using-imports"><strong>Split configs using imports</strong></h4>
<pre><code class="lang-apache"><span class="hljs-attribute">import</span> sites/*.caddy
<span class="hljs-attribute">import</span> snippets/*.caddy
</code></pre>
<h4 id="heading-example-structure"><strong>Example structure</strong></h4>
<pre><code class="lang-apache"><span class="hljs-attribute">caddy</span>/
 ├── <span class="hljs-attribute">Caddyfile</span>
 ├── <span class="hljs-attribute">sites</span>/
 │   ├── <span class="hljs-attribute">blog</span>.caddy
 │   ├── <span class="hljs-attribute">api</span>.caddy
 │   └── <span class="hljs-attribute">dashboard</span>.caddy
 └── <span class="hljs-attribute">snippets</span>/
     ├── <span class="hljs-attribute">security</span>.caddy
     ├── <span class="hljs-attribute">compression</span>.caddy
     └── <span class="hljs-attribute">caching</span>.caddy
</code></pre>
<p><strong>Each site file contains only its site block:</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">blog</span>.example.com {
    <span class="hljs-attribute">import</span> security_headers
    <span class="hljs-attribute">import</span> compression
    <span class="hljs-attribute">reverse_proxy</span> localhost:<span class="hljs-number">3000</span>
}
</code></pre>
<p>Using default paths keeps things simple, while custom paths and structured imports give you the flexibility needed for real-world applications. Caddy lets you start small and scale your configuration naturally — without rewriting everything later.</p>
<hr />
<h2 id="heading-7-setting-up-caddy-on-a-server"><strong>7. Setting Up Caddy on a Server</strong></h2>
<p>Okay, Let’s walk through a real-world server setup using caddy, where we will host a Laravel/PHP application and another is a static react application.</p>
<h3 id="heading-71-installing-caddy-on-a-linux-server"><strong>7.1 Installing Caddy on a Linux Server</strong></h3>
<p>To install Caddy on a Linux-based operating system, follow the installation part in this article above.</p>
<h4 id="heading-enabling-the-caddy-service"><strong>Enabling the Caddy service</strong></h4>
<p>Once installed, Caddy runs as a system service, we just need to start the service.</p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> caddy
sudo systemctl start caddy
</code></pre>
<p><strong>Verify it’s running:</strong></p>
<pre><code class="lang-bash">sudo systemctl status caddy
</code></pre>
<p>This makes Caddy suitable for long-running, unattended production systems.</p>
<p>Now you need to just point your domain to the server, like if your domain name is <strong><em>myblog.com</em></strong> and your API backend will be <strong><em>api.myblog.com</em></strong> then you need to point your DNS of this urls to your server like if your server IP address like this: 104.122.11.23 then your DNS record will be.</p>
<pre><code class="lang-bash">myblog.com      →  104.122.11.23
api.myblog.com  →  104.122.11.23
</code></pre>
<h3 id="heading-72-hosting-multiple-websites-on-one-server"><strong>7.2 Hosting Multiple Websites on One Server</strong></h3>
<p><strong>Assumptions</strong></p>
<ul>
<li><p>Laravel is deployed at: <code>/var/www/blog/laravel-app</code></p>
</li>
<li><p>PHP-FPM is running (e.g. PHP 8.4)</p>
</li>
<li><p>Laravel’s public directory is: <code>/var/www/blog/laravel-app/public</code></p>
</li>
<li><p>React build output is located at: <code>/var/www/blog/react-app/dist</code></p>
</li>
<li><p>App uses client-side routing (React Router)</p>
</li>
</ul>
<p>Now let’s update our caddyfile, at first it will comes with some dummy code, let’s remove it and rewrite.</p>
<p>by running this command in your server terminal <code>sudo nano /etc/caddy/Caddyfile</code> the file will be open for edit. Now in this file remove all of it’s content and put the below code.</p>
<pre><code class="lang-apache">{
    <span class="hljs-attribute">email</span> admin@example.com
}

<span class="hljs-attribute">myblog</span>.com {
    <span class="hljs-attribute">root</span> * /var/www/react-app/dist

    <span class="hljs-attribute">file_server</span>
    <span class="hljs-attribute">encode</span> zstd gzip

    <span class="hljs-attribute">try_files</span> {path} /index.html
}

<span class="hljs-attribute">api</span>.myblog.com {
    <span class="hljs-attribute">root</span> * /var/www/blog/laravel-app/public

    <span class="hljs-attribute">php_fastcgi</span> unix//run/php/php<span class="hljs-number">8</span>.<span class="hljs-number">4</span>-fpm.sock
    <span class="hljs-attribute">file_server</span>

    <span class="hljs-attribute">encode</span> zstd gzip
}
</code></pre>
<p>Now restart your caddy service by <code>sudo systemctl restart caddy</code> and your site will be live.</p>
<h3 id="heading-73-caddy-as-a-reverse-proxy"><strong>7.3 Caddy as a Reverse Proxy</strong></h3>
<p>In most cases, we use a reverse proxy in the server to run some dynamic applications. In such cases, Caddy provides a simple solution.</p>
<p>Let’s create a simple caddy proxy, where our application is serve by open it’s port to 3000.</p>
<h4 id="heading-simple-reverse-proxy-for-port-3000">Simple reverse proxy for port 3000</h4>
<pre><code class="lang-apache"><span class="hljs-attribute">example</span>.com {
    <span class="hljs-attribute">reverse_proxy</span> localhost:<span class="hljs-number">3000</span>
}
</code></pre>
<p>But most of the cases we do more like some health check, forwarding some headers also want to catch the error while the proxy is down or something wrong.</p>
<p>For this Let’s create a snippets for all of it configuration.</p>
<p><strong>Backend Snippets (Advanced)</strong></p>
<pre><code class="lang-apache">
(<span class="hljs-attribute">proxy_backend</span>) {
    <span class="hljs-attribute">reverse_proxy</span> {args[<span class="hljs-number">0</span>:]} {
        <span class="hljs-comment"># Load balancing</span>
        <span class="hljs-attribute">lb_policy</span> least_conn

        <span class="hljs-comment"># Health checks</span>
        <span class="hljs-attribute">health_uri</span> /up
        <span class="hljs-attribute">health_interval</span> <span class="hljs-number">10</span>s
        <span class="hljs-attribute">health_timeout</span> <span class="hljs-number">5</span>s
        <span class="hljs-attribute">health_status</span> <span class="hljs-number">2</span>xx

        <span class="hljs-comment"># Transport timeouts</span>
        <span class="hljs-attribute">transport</span> http {
            <span class="hljs-attribute">dial_timeout</span> <span class="hljs-number">2</span>s
            <span class="hljs-attribute">response_header_timeout</span> <span class="hljs-number">30</span>s
        }

        <span class="hljs-comment"># Forward real client information</span>
        <span class="hljs-comment"># header_up Host {upstream_hostport}</span>
        <span class="hljs-attribute">header_up</span> X-Real-IP {remote_host}
        <span class="hljs-attribute">header_up</span> X-Forwarded-Port {server_port}
    }

    <span class="hljs-comment"># Graceful fallback on upstream failure</span>
    <span class="hljs-attribute">handle_errors</span> {
        <span class="hljs-attribute">respond</span> <span class="hljs-string">"Service temporarily unavailable. Please try again later."</span> <span class="hljs-number">503</span>
    }
}
</code></pre>
<p>Now create another site with this proxy_backend snippet.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">api</span>.example.com {
    <span class="hljs-comment"># For single upstream</span>
    <span class="hljs-attribute">import</span> proxy_backend localhost:<span class="hljs-number">4000</span>

    <span class="hljs-comment"># For multiple upstream</span>
    <span class="hljs-attribute">import</span> proxy_backend localhost:<span class="hljs-number">4400</span> localhost:<span class="hljs-number">4200</span>
}
</code></pre>
<hr />
<h2 id="heading-8-running-caddy-with-docker"><strong>8. Running Caddy with Docker</strong></h2>
<p>The most straightforward way to begin using the Caddy server is by utilizing the official <a target="_blank" href="https://hub.docker.com/_/caddy">Docker image</a> and running Caddy as a Docker container. This approach guarantees a smooth installation process that is also relatively straightforward to replicate on various systems.</p>
<h3 id="heading-81-basic-docker-usage"><strong>8.1 Basic Docker Usage</strong></h3>
<h4 id="heading-pull-and-run-the-official-image"><strong>Pull and run the official image</strong></h4>
<p>A practical baseline is: publish ports 80/443, mount your Caddyfile, mount your site files, and attach persistent volumes for /data and /config.</p>
<pre><code class="lang-bash">docker pull caddy:latest
</code></pre>
<p>Create a Caddyfile and run the command below after making changes in caddy file.</p>
<p><strong>Caddyfile</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">localhost</span> {
    <span class="hljs-attribute">tls</span> internal
    <span class="hljs-attribute">root</span> * /usr/share/caddy
    <span class="hljs-attribute">file_server</span>
}
</code></pre>
<p>Then run this command.</p>
<pre><code class="lang-bash">docker run -d \
  --name caddy-server \
  -p 80:80 -p 443:443 -p 443:443/udp -p 8000:80 \
  -v <span class="hljs-variable">$PWD</span>/Caddyfile:/etc/caddy/Caddyfile:ro \
  -v caddy_data:/data \
  -v caddy_config:/config \
  --restart unless-stopped \
  caddy:latest
</code></pre>
<p>Then browse in your browser: https://localhost and you will see the caddy welcome page like below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765988508542/7cce87a1-20f0-410f-add6-0344646b7ace.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-82-docker-compose-multi-site-setup"><strong>8.2 Docker Compose Multi-Site Setup</strong></h3>
<p>Okay, that’s a great start, right? Let’s move on to doing some real work.</p>
<p>Imagine our application architecture like this:</p>
<pre><code class="lang-bash">Browser
  ↓
Caddy (Edge / Gateway)
  ├── Static React build
  └── Reverse proxy → Node API container
</code></pre>
<p>First, create our actual project directory structure.</p>
<pre><code class="lang-bash">caddy-local/
├── docker-compose.yml
├── Caddyfile
└── sites/
    └── app/
        └── index.html
    └── api/
        ├── Dockerfile
        └── index.js
</code></pre>
<p>This keeps infra, config, and content properly decoupled.</p>
<p><strong>docker-compose.yml (Single Source of Truth)</strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">myapp</span>

<span class="hljs-attr">services:</span>
  <span class="hljs-attr">caddy:</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">caddy</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">caddy</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'80:80'</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'443:443'</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">caddy-config:/config</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">caddy-data:/data</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./Caddyfile:/etc/caddy/Caddyfile</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./sites:/srv</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">backend</span>

  <span class="hljs-attr">backend:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./sites/api</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">node_backend</span>
    <span class="hljs-attr">expose:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000"</span>

<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">caddy-config:</span>
  <span class="hljs-attr">caddy-data:</span>
</code></pre>
<p>In your <strong>Caddyfile</strong></p>
<pre><code class="lang-apache"><span class="hljs-attribute">app</span>.test {
    <span class="hljs-comment"># React Router (SPA)</span>
    <span class="hljs-attribute">root</span> * /srv/app
    <span class="hljs-attribute">file_server</span>
    <span class="hljs-attribute">try_files</span> {path} /index.html

    <span class="hljs-comment"># API</span>
    <span class="hljs-attribute">handle_path</span> /api/* {
        <span class="hljs-attribute">reverse_proxy</span> backend:<span class="hljs-number">3000</span>
    }

    <span class="hljs-attribute">tls</span> internal
}

<span class="hljs-attribute">api</span>.app.test {
    <span class="hljs-attribute">tls</span> internal
    <span class="hljs-attribute">reverse_proxy</span> backend:<span class="hljs-number">3000</span>
}
</code></pre>
<p>API App <strong>dockerfile</strong> will be</p>
<pre><code class="lang-bash">FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]
</code></pre>
<p>Now we have to map the hosts to docker and local machine, so let’s do it by open hosts file <code>sudo nano /etc/hosts</code></p>
<pre><code class="lang-bash">127.0.0.1 app.test
127.0.0.1 api.app.test
</code></pre>
<p>Then build and trust</p>
<pre><code class="lang-bash">docker compose up --build -d

docker <span class="hljs-built_in">exec</span> -it caddy caddy trust
</code></pre>
<p>You can now access your site by your defined domain easily.</p>
<hr />
<h2 id="heading-9-using-the-caddy-api"><strong>9. Using the Caddy API</strong></h2>
<p>Caddy isn’t just a static web server — its <strong>API allows you to change configuration dynamically</strong> without editing the Caddyfile or restarting the server. This is especially powerful for <strong>automated deployments, dynamic routing, and integrations with CI/CD pipelines</strong>.</p>
<h3 id="heading-91-what-the-api-does"><strong>9.1 What the API Does</strong></h3>
<p>The <strong>Caddy API</strong> provides endpoints to:</p>
<ul>
<li><p>Add, remove, or modify site blocks</p>
</li>
<li><p>Enable or disable routes</p>
</li>
<li><p>Adjust global settings (logging, TLS, compression)</p>
</li>
<li><p>Inspect server status or loaded configuration</p>
</li>
</ul>
<p>Unlike editing a Caddyfile manually, the API applies changes <strong>on-the-fly</strong>, making it ideal for automation</p>
<h3 id="heading-92-practical-use-cases"><strong>9.2 Practical Use Cases</strong></h3>
<h4 id="heading-example-1-dynamic-domain-addition"><strong>Example 1: Dynamic Domain Addition</strong></h4>
<p>Imagine a SaaS platform where new users get custom subdomains. You can programmatically add routes via the API.</p>
<p><strong>Request example (add new site block)</strong></p>
<pre><code class="lang-bash">curl -X POST <span class="hljs-string">"http://localhost:2019/config/apps/http/servers/srv0/routes"</span> \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{
    "match": [{"host": ["newuser.example.com"]}],
    "handle": [{
        "handler": "reverse_proxy",
        "upstreams": [{"dial": "127.0.0.1:4001"}]
    }]
}'</span>
</code></pre>
<p>No restart or downtime is required.</p>
<h4 id="heading-example-2-automated-deployments"><strong>Example 2: Automated Deployments</strong></h4>
<p>Suppose you deploy a new React frontend build. After uploading static files, you might want to:</p>
<ul>
<li><p>Clear cache rules</p>
</li>
<li><p>Update file server paths</p>
</li>
<li><p>Apply gzip or Brotli compression</p>
</li>
</ul>
<p>Instead of editing the Caddyfile manually, you can send a POST request to the API to update the configuration automatically as part of your <strong>CI/CD pipeline</strong>.</p>
<pre><code class="lang-bash">curl -X POST <span class="hljs-string">"http://localhost:2019/config/apps/http/servers/srv0/routes"</span> \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{
    "match": [{"host": ["app.example.com"]}],
    "handle": [{
        "handler": "file_server",
        "root": "/srv/react-dist-new"
    }]
}'</span>
</code></pre>
<h4 id="heading-example-3-on-the-fly-routing-changes"><strong>Example 3: On-the-Fly Routing Changes</strong></h4>
<p>If an upstream service fails or you want <strong>blue-green deployments</strong>, the API can redirect traffic dynamically:</p>
<pre><code class="lang-bash">curl -X POST <span class="hljs-string">"http://localhost:2019/config/apps/http/servers/srv0/routes"</span> \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{
    "match": [{"host": ["api.example.com"]}],
    "handle": [{
        "handler": "reverse_proxy",
        "upstreams": [{"dial": "127.0.0.1:5000"}]
    }]
}'</span>
</code></pre>
<p>The switch is instantaneous, and old traffic is immediately routed to the new backend.</p>
<h3 id="heading-93-securing-the-api"><strong>9.3 Securing the API</strong></h3>
<p>Because the API allows full configuration changes, <strong>security is critical</strong>.</p>
<h4 id="heading-best-practices"><strong>Best practices:</strong></h4>
<ol>
<li><strong>Bind to</strong> <a target="_blank" href="http://localhost"><strong>localhost</strong></a> <strong>or private network</strong></li>
</ol>
<pre><code class="lang-bash">{
  <span class="hljs-string">"admin"</span>: {
    <span class="hljs-string">"listen"</span>: <span class="hljs-string">"127.0.0.1:2019"</span>
  }
}
</code></pre>
<p>Never expose the API directly to the public internet.</p>
<ol start="2">
<li><p><strong>Use firewall rules or VPN</strong></p>
<ul>
<li>Only trusted servers or CI/CD runners should access the API.</li>
</ul>
</li>
</ol>
<ol start="3">
<li><p><strong>Authentication</strong></p>
<ul>
<li>For production, consider using a reverse proxy in front of the API with basic auth or token validation.</li>
</ul>
</li>
<li><p><strong>Audit changes</strong></p>
<ul>
<li><p>Log all API requests.</p>
</li>
<li><p>Optionally, integrate with monitoring tools to detect unexpected modifications.</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-10-best-practices"><strong>10. Best Practices</strong></h2>
<p>When working with Caddy, following a few <strong>simple best practices</strong> can make your configuration easier to maintain and your server more reliable.</p>
<p><strong>Use Snippets Where Possible</strong></p>
<p>Snippets are reusable blocks of configuration. For example, you can create a snippet for security headers, caching rules, or reverse proxy settings and then include it in multiple site blocks. This <strong>avoids repetition</strong> and keeps your Caddyfile clean. Instead of copying the same directives across many sites, just import the snippet wherever you need it.</p>
<p><strong>Keep Site Blocks Readable</strong></p>
<p>Even with multiple sites, try to <strong>organize your Caddyfile clearly</strong>. Group related settings together, use comments to explain why certain directives are there, and separate large configurations into multiple files if needed. Readable configuration makes it much easier to troubleshoot issues or onboard new team members.</p>
<p><strong>Avoid Unnecessary Directives</strong></p>
<p>Only include the directives your site actually needs. Extra or unused settings can <strong>confuse Caddy</strong> or create unexpected behavior. Focus on what matters for each site: SSL, reverse proxy targets, caching, and logging. Minimal, precise configuration is easier to manage and less prone to errors.</p>
<p><strong>Enable Logging and Monitoring</strong></p>
<p>Always enable access and error logs, even in development. Logs help you <strong>understand traffic patterns, catch issues early, and debug problems quickly</strong>. For production setups, consider combining Caddy logs with monitoring tools to get alerts when a site is down or an upstream service is failing.</p>
<p>By following these practices, you can build <strong>scalable, maintainable, and reliable Caddy configurations</strong>, whether you’re hosting a single site or dozens of applications.</p>
<hr />
<h2 id="heading-11-common-pitfalls-amp-how-to-avoid-them"><strong>11. Common Pitfalls &amp; How to Avoid Them</strong></h2>
<p>Even though Caddy is beginner-friendly, there are a few <strong>common mistakes</strong> that can trip up developers and system administrators. Knowing these in advance will save you a lot of time and frustration.</p>
<p><strong>1. DNS Issues</strong></p>
<p>Caddy relies on DNS to issue certificates and route traffic. If your domain doesn’t point to the correct server, <strong>automatic HTTPS will fail</strong>, or users won’t reach your site.</p>
<p><strong>How to avoid:</strong></p>
<ul>
<li><p>Double-check A/AAAA records for your domains.</p>
</li>
<li><p>For subdomains, ensure they’re correctly set in DNS.</p>
</li>
<li><p>Use dig or nslookup to verify the records before starting Caddy.</p>
</li>
<li><p>For local development, check your <code>/etc/hosts</code> file.</p>
</li>
</ul>
<p><strong>2. Wrong File Permissions</strong></p>
<p>Caddy needs proper access to site files, Caddyfile, and data directories. If permissions are too restrictive, Caddy may <strong>fail to serve files or write certificates</strong>.</p>
<p><strong>How to avoid:</strong></p>
<ul>
<li><p>Ensure the Caddy user (or container user) can read site files and write to /data and /config.</p>
</li>
<li><p>On Linux: chown -R caddy:caddy /srv /etc/caddy /data /config</p>
</li>
<li><p>Avoid giving overly broad permissions; balance security and accessibility.</p>
</li>
</ul>
<p><strong>3. Misconfigured Docker Paths</strong></p>
<p>When running Caddy in Docker, it’s common to <strong>mount the wrong paths</strong> or forget to include volumes for /data and /config. This can lead to missing TLS certificates or failed site builds.</p>
<p><strong>How to avoid:</strong></p>
<ul>
<li>Mount your Caddyfile and site directories correctly:</li>
</ul>
<pre><code class="lang-bash">- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./site:/srv:ro
- caddy_data:/data
- caddy_config:/config
</code></pre>
<ul>
<li>Always use <strong>persistent volumes</strong> for certificates to prevent re-issuing on container restart.</li>
</ul>
<p><strong>4. Forgetting to Reload Config</strong></p>
<p>Caddy can apply configuration dynamically via the API or Caddyfile reload, but <strong>forgetting to reload</strong> after edits means your changes won’t take effect.</p>
<p><strong>How to avoid:</strong></p>
<ul>
<li>Use caddy reload after editing Caddyfile:</li>
</ul>
<pre><code class="lang-bash">caddy reload --config /etc/caddy/Caddyfile
</code></pre>
<ul>
<li>For Docker, you can reload inside the container:</li>
</ul>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> caddy caddy reload --config /etc/caddy/Caddyfile
</code></pre>
<ul>
<li>For automated workflows, consider using the <strong>Caddy API</strong> to apply changes on-the-fly.</li>
</ul>
<hr />
<h2 id="heading-12-conclusion"><strong>12. Conclusion</strong></h2>
<p>Caddy offers a <strong>refreshing approach to web servers</strong>. Unlike traditional servers that require long, complex configurations and manual SSL management, Caddy makes it easy to get sites up and running with <strong>automatic HTTPS, clean configuration syntax, and built-in features</strong> like reverse proxying, load balancing, and file serving.</p>
<p>Its simplicity <strong>reduces developer overhead</strong>, letting you focus on building applications instead of fighting with server setups. Whether you’re working on a local development environment for a Laravel or React app, or deploying multiple sites in production, Caddy handles the heavy lifting behind the scenes — TLS, routing, and health checks are taken care of automatically.</p>
<p>For developers and teams who value <strong>speed, security, and maintainability</strong>, trying Caddy is a no-brainer. Start small with a local project, explore snippets, multi-site configurations, and the API, and you’ll quickly see why many consider it one of the most developer-friendly web servers available today.</p>
<p><strong>Give it a try — you might never look back at traditional web servers again. If you need more help or suggestions, please don’t hesitate to ask me. I’d be more than happy to assist you.</strong></p>
<hr />
<h3 id="heading-resources">Resources:</h3>
<ul>
<li><p><a target="_blank" href="https://caddyserver.com/docs/getting-started">https://caddyserver.com/docs/getting-started</a></p>
</li>
<li><p><a target="_blank" href="https://betterstack.com/community/guides/web-servers/caddy/">https://betterstack.com/community/guides/web-servers/caddy/</a></p>
</li>
<li><p><a target="_blank" href="https://caddyserver.com/docs/api">https://caddyserver.com/docs/api</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/4msar/41111d5b10f347ff44ccb939c144b557">Custom snippets</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A Bash Script for Default File Associations]]></title><description><![CDATA[As a software engineer, juggling files in dozens of formats—from source code to config and markup—is a daily reality. Opening these files in the right editor is crucial for productivity, yet macOS doesn't always make it easy to set your preferred edi...]]></description><link>https://blog.msar.me/a-bash-script-for-default-file-associations</link><guid isPermaLink="true">https://blog.msar.me/a-bash-script-for-default-file-associations</guid><category><![CDATA[Default Editor]]></category><category><![CDATA[Bash]]></category><category><![CDATA[Scripting]]></category><category><![CDATA[tools]]></category><category><![CDATA[unix]]></category><category><![CDATA[macOS]]></category><category><![CDATA[macOS Tips]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 11 Aug 2025 06:06:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Vydl03oO7ZQ/upload/95cbae827269af1d56c84c305e0ef760.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a software engineer, juggling files in dozens of formats—from source code to config and markup—is a daily reality. Opening these files in the right editor is crucial for productivity, yet macOS doesn't always make it easy to set your preferred editor for every relevant extension. Recently, I ran into this challenge: I wanted all my engineering-related files to open in Zed, my favorite lightweight editor. Here’s how I solved that problem quickly using a Bash script.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Before my solution, every time I encountered a new file type—say, a <code>.tsx</code> React file, a <code>.dockerignore</code> config, or even obscure extensions like <code>.erl</code> for Erlang—I had to manually set the default app for that format. It was slow and tedious, and often required digging into system settings or context menus. As my project stack grew to include new languages and frameworks, this became unmanageable.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>I decided to automate the entire process using a purpose-built Bash script and the macOS tool <code>duti</code>. <code>duti</code> allows command-line management of file associations, making it perfect for bulk operations.</p>
<h2 id="heading-building-the-script">Building the Script</h2>
<p>The heart of the solution lay in combining two ideas:</p>
<ul>
<li><p><strong>A comprehensive list of extensions</strong> relevant to software engineering (covering everything from <code>.c</code> for C, <code>.py</code> for Python, to <code>.yaml</code> for config files).</p>
</li>
<li><p><strong>Automation with Bash</strong>, looping through the list and setting Zed as the default app for each file type.</p>
</li>
</ul>
<p>Here’s the script I used:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># My Editor Id, you can get your desired editor id by running `osascript -e 'id of app "Visual Studio Code"'`</span>
ZED_ID=<span class="hljs-string">"dev.zed.Zed"</span>

EXTENSIONS=(
  <span class="hljs-string">"c"</span> <span class="hljs-string">"cpp"</span> <span class="hljs-string">"cc"</span> <span class="hljs-string">"h"</span> <span class="hljs-string">"hpp"</span>
  <span class="hljs-string">"java"</span> <span class="hljs-string">"class"</span>
  <span class="hljs-string">"js"</span> <span class="hljs-string">"jsx"</span> <span class="hljs-string">"ts"</span> <span class="hljs-string">"tsx"</span>
  <span class="hljs-string">"py"</span> <span class="hljs-string">"pyw"</span>
  <span class="hljs-string">"rb"</span>
  <span class="hljs-string">"sh"</span> <span class="hljs-string">"bash"</span>
  <span class="hljs-string">"bat"</span> <span class="hljs-string">"cmd"</span>
  <span class="hljs-string">"go"</span>
  <span class="hljs-string">"php"</span>
  <span class="hljs-string">"swift"</span>
  <span class="hljs-string">"cs"</span>
  <span class="hljs-string">"pl"</span> <span class="hljs-string">"pm"</span>
  <span class="hljs-string">"lua"</span>
  <span class="hljs-string">"kt"</span> <span class="hljs-string">"kts"</span>
  <span class="hljs-string">"scala"</span>
  <span class="hljs-string">"rs"</span>
  <span class="hljs-string">"r"</span>
  <span class="hljs-string">"dart"</span>
  <span class="hljs-comment"># skip this cause it should open in browser by default</span>
  <span class="hljs-comment"># "html" "htm" "xhtml"</span>
  <span class="hljs-string">"xml"</span> <span class="hljs-string">"json"</span> <span class="hljs-string">"yml"</span> <span class="hljs-string">"yaml"</span>
  <span class="hljs-string">"css"</span> <span class="hljs-string">"scss"</span> <span class="hljs-string">"sass"</span> <span class="hljs-string">"less"</span>
  <span class="hljs-string">"md"</span>
  <span class="hljs-string">"sql"</span>
  <span class="hljs-string">"asm"</span> <span class="hljs-string">"s"</span>
  <span class="hljs-string">"m"</span> <span class="hljs-string">"mm"</span>
  <span class="hljs-string">"ex"</span> <span class="hljs-string">"exs"</span>
  <span class="hljs-string">"erl"</span>
  <span class="hljs-string">"hs"</span>
  <span class="hljs-string">"lisp"</span> <span class="hljs-string">"cl"</span>
  <span class="hljs-string">"groovy"</span>
  <span class="hljs-string">"fs"</span> <span class="hljs-string">"fsi"</span> <span class="hljs-string">"fsx"</span>
  <span class="hljs-string">"vue"</span>
  <span class="hljs-string">"coffee"</span>
  <span class="hljs-string">"ini"</span> <span class="hljs-string">"conf"</span> <span class="hljs-string">"cfg"</span> <span class="hljs-string">"toml"</span> <span class="hljs-string">"env"</span>
  <span class="hljs-string">"dockerfile"</span> <span class="hljs-string">"dockerignore"</span>
  <span class="hljs-string">"gemspec"</span> <span class="hljs-string">"gradle"</span> <span class="hljs-string">"pom.xml"</span>
  <span class="hljs-string">"lock"</span> <span class="hljs-string">"package"</span> <span class="hljs-string">"yarn.lock"</span>
  <span class="hljs-string">"pbxproj"</span> <span class="hljs-string">"xcworkspace"</span> <span class="hljs-string">"xcodeproj"</span>
  <span class="hljs-string">"sln"</span> <span class="hljs-string">"csproj"</span> <span class="hljs-string">"vbproj"</span>
  <span class="hljs-string">"make"</span> <span class="hljs-string">"mak"</span> <span class="hljs-string">"mk"</span>
  <span class="hljs-string">"gitignore"</span> <span class="hljs-string">"gitattributes"</span>
  <span class="hljs-string">"proto"</span>
  <span class="hljs-string">"f90"</span> <span class="hljs-string">"f"</span> <span class="hljs-string">"for"</span>
  <span class="hljs-string">"pas"</span>
  <span class="hljs-string">"adb"</span> <span class="hljs-string">"ads"</span>
  <span class="hljs-string">"matlab"</span>
  <span class="hljs-string">"ps1"</span>
  <span class="hljs-string">"hbs"</span>
  <span class="hljs-string">"jade"</span> <span class="hljs-string">"pug"</span>
  <span class="hljs-string">"ejs"</span>
  <span class="hljs-string">"tpl"</span>
)
<span class="hljs-keyword">for</span> ext <span class="hljs-keyword">in</span> <span class="hljs-string">"<span class="hljs-variable">${EXTENSIONS[@]}</span>"</span>; <span class="hljs-keyword">do</span>
  duti -s <span class="hljs-string">"<span class="hljs-variable">$ZED_ID</span>"</span> .<span class="hljs-variable">$ext</span> all
<span class="hljs-keyword">done</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"All specified code file extensions are now set to open with Zed."</span>
</code></pre>
<h2 id="heading-how-it-worked">How It Worked</h2>
<ul>
<li><p><strong>Single command execution:</strong> Instead of manually changing settings for each extension, I saved this script as <code>associate_</code><a target="_blank" href="http://zed.sh"><code>zed.sh</code></a>, made it executable, and ran it once.</p>
</li>
<li><p><strong>Instant results:</strong> Every file with an extension in the list now opens seamlessly in Zed across Finder and other apps.</p>
</li>
<li><p><strong>Easy maintenance:</strong> If I start working in a new language, I just add its extension to the <code>EXTENSIONS</code> array and rerun the script.</p>
</li>
</ul>
<h2 id="heading-impact-on-my-workflow">Impact on My Workflow</h2>
<ul>
<li><p><strong>No more interruptions:</strong> I never have to deal with files opening in the wrong editor or having to right-click and choose "Open With..." ever again.</p>
</li>
<li><p><strong>Onboarding made easy:</strong> Sharing the script with teammates lets everyone standardize their dev environment with a single command.</p>
</li>
<li><p><strong>Adaptable:</strong> If I ever switch to a different editor, I only need to change the <code>ZED_ID</code> variable.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Automating file extension associations rescued me from a frustrating, repetitive setup process and turned onboarding into a breeze. For anyone who spends their day immersed in code across a spectrum of formats, this simple Bash script is a game-changer.</p>
<p>The time saved lets me focus on actual engineering work—not wrangling file associations. If you’re using Zed (or any editor), I highly recommend this approach to dramatically simplify your dev environment setup.</p>
<p><em><mark>You can find my code in this </mark></em> <a target="_blank" href="https://gist.github.com/4msar/7c8ba1d3fe247bf6043ebde194f6c504"><em><mark>gist</mark></em></a> <em><mark> also.</mark></em></p>
]]></content:encoded></item><item><title><![CDATA[Automating Laravel & Vue.js (Inertia) Releases with GitHub Actions]]></title><description><![CDATA[As developers, we love to build things. We pour our hearts and minds into creating applications that solve real-world problems. But when it comes to shipping our creations, the process can often be a tedious, repetitive, and error-prone chore. Manual...]]></description><link>https://blog.msar.me/automating-laravel-and-vuejs-inertia-releases-with-github-actions</link><guid isPermaLink="true">https://blog.msar.me/automating-laravel-and-vuejs-inertia-releases-with-github-actions</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[automation]]></category><category><![CDATA[automation tools]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Inertia.js]]></category><category><![CDATA[Vue.js]]></category><category><![CDATA[deployment]]></category><category><![CDATA[release management]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Wed, 02 Jul 2025 03:00:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751353412251/aedc2a72-223f-4919-9ef3-bed20a263a6f.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As developers, we love to build things. We pour our hearts and minds into creating applications that solve real-world problems. But when it comes to shipping our creations, the process can often be a tedious, repetitive, and error-prone chore. Manual releases are a time sink, and let's be honest, they're not the most exciting part of our job.</p>
<p>What if I told you there's a better way? A way to make your release process seamless, consistent, and fully automated. In this article, I'll walk you through how I automated the entire release workflow for my project, "Bill Organizer," a Laravel and Vue.js application. We'll take a deep dive into the GitHub Actions workflow I created, breaking it down step-by-step, and exploring the "how," the "what," and the "why" behind it.</p>
<p>By the end of this article, you'll have a clear understanding of how to build your own automated release pipeline, saving you time, reducing the risk of human error, and allowing you to focus on what you do best: writing code.</p>
<h2 id="heading-the-problem-with-manual-releases">The Problem with Manual Releases</h2>
<p>Before we jump into the solution, let's talk about the pain points of manual releases. If you've ever been responsible for deploying an application, some of these might sound familiar:</p>
<ul>
<li><p><strong>Time-Consuming:</strong> The process of pulling the latest code, installing dependencies, building assets, running tests, versioning, creating a changelog, and finally deploying can take a significant amount of time.</p>
</li>
<li><p><strong>Error-Prone:</strong> With so many steps involved, it's easy to make a mistake. Forgetting to install a dependency, building with the wrong environment variables, or making a typo in a version number can all lead to a broken release.</p>
</li>
<li><p><strong>Inconsistent:</strong> When different team members handle releases, they might do things slightly differently. This can lead to inconsistencies in your build artifacts and release notes.</p>
</li>
<li><p><strong>Lack of Visibility:</strong> It can be difficult to track what's in each release, especially if you're not diligent about keeping a changelog.</p>
</li>
</ul>
<p>Automating your release process helps to solve all of these problems. It ensures that every release is built and deployed in exactly the same way, every single time.</p>
<h2 id="heading-the-goal-a-fully-automated-release-pipeline">The Goal: A Fully Automated Release Pipeline</h2>
<p>For my "<a target="_blank" href="https://github.com/4msar/bill-organizer">Bill Organizer</a>" project, I had a clear set of goals for my automated release system:</p>
<ol>
<li><p><strong>Trigger on Push to</strong> <code>main</code>: I wanted the release process to kick off automatically every time I pushed new commits to the <code>main</code> branch.</p>
</li>
<li><p><strong>Semantic Versioning:</strong> I wanted to automatically generate a new semantic version number (e.g., <code>v1.2.3</code>) for each release, incrementing the patch version each time.</p>
</li>
<li><p><strong>Build for Production:</strong> The workflow should install all the necessary dependencies (both PHP and Node.js), build the frontend assets, and create a production-ready application.</p>
</li>
<li><p><strong>Create a Production Archive:</strong> The system should generate a clean, production-only <code>.zip</code> archive, excluding all development files and dependencies.</p>
</li>
<li><p><strong>Generate a GitHub Release:</strong> A new draft release should be created on GitHub for each new version.</p>
</li>
<li><p><strong>Automated Changelog:</strong> The release notes should automatically include a list of all the commit messages since the last release.</p>
</li>
<li><p><strong>Upload Artifacts:</strong> The <code>.zip</code> archive should be uploaded as an artifact to the GitHub release.</p>
</li>
</ol>
<p>With these goals in mind, I turned to GitHub Actions, a powerful and flexible CI/CD platform that's built right into GitHub.</p>
<h2 id="heading-the-workflow-a-step-by-step-breakdown">The Workflow: A Step-by-Step Breakdown</h2>
<p>Let's dive into the <a target="_blank" href="https://raw.githubusercontent.com/4msar/bill-organizer/main/.github/workflows/release.yml"><code>release.yml</code></a> workflow file and break down each section.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Release</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">workflow_dispatch:</span>

<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">packages:</span> <span class="hljs-string">write</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">release:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
</code></pre>
<h3 id="heading-triggering-the-workflow">Triggering the Workflow</h3>
<p>The <code>on</code> section defines when the workflow will run. In this case, it's triggered in two ways:</p>
<ul>
<li><p><code>push: branches: [main]</code>: This is the primary trigger. Every time new commits are pushed to the <code>main</code> branch, this workflow will be executed. This is the heart of our continuous delivery pipeline.</p>
</li>
<li><p><code>workflow_dispatch:</code>: This allows me to trigger the workflow manually from the GitHub UI. This is useful for re-running a release or for testing purposes.</p>
</li>
</ul>
<h3 id="heading-permissions">Permissions</h3>
<p>The <code>permissions</code> block is crucial for security. It defines the permissions that the <code>GITHUB_TOKEN</code> will have for this workflow. By default, the token is read-only. We need to grant it some write permissions:</p>
<ul>
<li><p><code>contents: write</code>: This is required to create a GitHub release and to push tags.</p>
</li>
<li><p><code>packages: write</code>: This is necessary if you're publishing packages to the GitHub Package Registry. While not strictly used for creating a release, it's good practice to have if you plan to extend your workflow in the future.</p>
</li>
</ul>
<h3 id="heading-the-release-job">The <code>release</code> Job</h3>
<p>Now we get to the meat of the workflow: the <code>release</code> job. This job runs on <code>ubuntu-latest</code>, which is a virtual machine hosted by GitHub.</p>
<h4 id="heading-1-checking-out-the-code">1. Checking Out the Code</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">repository</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">fetch-depth:</span> <span class="hljs-number">0</span>
</code></pre>
<p>The first step is to check out the repository's code. We use the <code>actions/checkout@v4</code> action for this. The <code>with: fetch-depth: 0</code> parameter is very important here. By default, <code>checkout</code> only fetches the latest commit. <code>fetch-depth: 0</code> tells the action to fetch the entire Git history, including all tags. We need this for our semantic versioning step later on.</p>
<h4 id="heading-2-setting-up-the-environment">2. Setting Up the Environment</h4>
<p>Next, we need to set up the build environment with all the necessary tools and dependencies.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">PHP</span> <span class="hljs-number">8.3</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">shivammathur/setup-php@v2</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">php-version:</span> <span class="hljs-string">'8.3'</span>
    <span class="hljs-attr">tools:</span> <span class="hljs-string">composer:v2</span>
    <span class="hljs-attr">extensions:</span> <span class="hljs-string">bcmath,</span> <span class="hljs-string">ctype,</span> <span class="hljs-string">fileinfo,</span> <span class="hljs-string">json,</span> <span class="hljs-string">mbstring,</span> <span class="hljs-string">openssl,</span> <span class="hljs-string">pdo,</span> <span class="hljs-string">tokenizer,</span> <span class="hljs-string">xml,</span> <span class="hljs-string">zip</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Get</span> <span class="hljs-string">Composer</span> <span class="hljs-string">cache</span> <span class="hljs-string">directory</span>
  <span class="hljs-attr">id:</span> <span class="hljs-string">composer-cache</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">echo</span> <span class="hljs-string">"dir=$(composer config cache-files-dir)"</span> <span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">$GITHUB_OUTPUT</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Cache</span> <span class="hljs-string">Composer</span> <span class="hljs-string">dependencies</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/cache@v4</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.composer-cache.outputs.dir</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-composer-${{</span> <span class="hljs-string">hashFiles('**/composer.lock')</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">restore-keys:</span> <span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-composer-</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Node.js</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">node-version:</span> <span class="hljs-string">'22'</span>
    <span class="hljs-attr">cache:</span> <span class="hljs-string">'yarn'</span>
</code></pre>
<ul>
<li><p><strong>Setup PHP:</strong> We use the <code>shivammathur/setup-php@v2</code> action to install PHP 8.3, Composer v2, and all the required PHP extensions for our Laravel application.</p>
</li>
<li><p><strong>Cache Composer Dependencies:</strong> Caching is a key optimization technique in CI/CD pipelines. We first get the Composer cache directory, then use the <code>actions/cache@v4</code> action to cache our Composer dependencies. The <code>key</code> is generated based on the operating system and a hash of the <code>composer.lock</code> file. If the <code>composer.lock</code> file hasn't changed, the cache will be restored, saving us from having to download all the dependencies again.</p>
</li>
<li><p><strong>Setup Node.js:</strong> Similarly, we use the <code>actions/setup-node@v4</code> action to install Node.js 22. The <code>cache: 'yarn'</code> option automatically handles caching for our Yarn dependencies.</p>
</li>
</ul>
<h4 id="heading-3-building-the-application">3. Building the Application</h4>
<p>With our environment set up, it's time to build the application.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Composer</span> <span class="hljs-string">dependencies</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">composer</span> <span class="hljs-string">install</span> <span class="hljs-string">--no-dev</span> <span class="hljs-string">--optimize-autoloader</span> <span class="hljs-string">--no-interaction</span> <span class="hljs-string">--prefer-dist</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Yarn</span> <span class="hljs-string">dependencies</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">environment</span> <span class="hljs-string">file</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">cp</span> <span class="hljs-string">.env.example</span> <span class="hljs-string">.env</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Generate</span> <span class="hljs-string">application</span> <span class="hljs-string">key</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">key:generate</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Publish</span> <span class="hljs-string">Ziggy</span> <span class="hljs-string">configuration</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">ziggy:generate</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Type</span> <span class="hljs-string">check</span> <span class="hljs-string">TypeScript</span> <span class="hljs-string">files</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">lint</span>

<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">frontend</span> <span class="hljs-string">assets</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
</code></pre>
<p>This is a series of standard build steps for a Laravel and Vue.js application:</p>
<ul>
<li><p>We install Composer dependencies with <code>--no-dev</code> to exclude development packages, and <code>--optimize-autoloader</code> for better performance.</p>
</li>
<li><p>We install Yarn dependencies using <code>--frozen-lockfile</code> to ensure we're using the exact versions specified in our <code>yarn.lock</code> file.</p>
</li>
<li><p>We then run our Laravel-specific build commands, such as generating an application key and publishing the Ziggy configuration.</p>
</li>
<li><p>Finally, we run <code>yarn lint</code> to check for any TypeScript errors and <code>yarn build</code> to compile our frontend assets for production.</p>
</li>
</ul>
<h4 id="heading-4-semantic-versioning">4. Semantic Versioning</h4>
<p>This is where the magic happens. This step automatically determines the next version number.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Generate</span> <span class="hljs-string">semantic</span> <span class="hljs-string">version</span>
  <span class="hljs-attr">id:</span> <span class="hljs-string">version</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|
    # Get the latest tag
    LATEST_TAG=$(git describe --tags --abbrev=0 2&gt;/dev/null || echo "v0.0.0")
    echo "Latest tag: $LATEST_TAG"
</span>
    <span class="hljs-comment"># Remove 'v' prefix if it exists</span>
    <span class="hljs-string">LATEST_VERSION=${LATEST_TAG#v}</span>

    <span class="hljs-comment"># Split version into parts</span>
    <span class="hljs-string">IFS='.'</span> <span class="hljs-string">read</span> <span class="hljs-string">-ra</span> <span class="hljs-string">VERSION_PARTS</span> <span class="hljs-string">&lt;&lt;&lt;</span> <span class="hljs-string">"$LATEST_VERSION"</span>
    <span class="hljs-string">MAJOR=${VERSION_PARTS[0]:-0}</span>
    <span class="hljs-string">MINOR=${VERSION_PARTS[1]:-0}</span>
    <span class="hljs-string">PATCH=${VERSION_PARTS[2]:-0}</span>

    <span class="hljs-comment"># Increment patch version</span>
    <span class="hljs-string">NEW_PATCH=$((PATCH</span> <span class="hljs-string">+</span> <span class="hljs-number">1</span><span class="hljs-string">))</span>
    <span class="hljs-string">NEW_VERSION="v${MAJOR}.${MINOR}.${NEW_PATCH}"</span>

    <span class="hljs-string">echo</span> <span class="hljs-string">"New version: $NEW_VERSION"</span>
    <span class="hljs-string">echo</span> <span class="hljs-string">"version=$NEW_VERSION"</span> <span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">$GITHUB_OUTPUT</span>
    <span class="hljs-string">echo</span> <span class="hljs-string">"version_number=${MAJOR}.${MINOR}.${NEW_PATCH}"</span> <span class="hljs-string">&gt;&gt;</span> <span class="hljs-string">$GITHUB_OUTPUT</span>
</code></pre>
<p>Here's how it works:</p>
<ol>
<li><p><code>git describe --tags --abbrev=0</code>: This command finds the most recent tag in the Git history. If no tags are found, it defaults to <code>v0.0.0</code>.</p>
</li>
<li><p>We then parse this tag, split it into major, minor, and patch components.</p>
</li>
<li><p>We increment the patch version by one.</p>
</li>
<li><p>Finally, we construct the new version string (e.g., <code>v1.2.4</code>) and output it as <code>version</code> and <code>version_number</code> for use in later steps. We use <code>id: version</code> to be able to reference these outputs later with <code>steps.version.outputs.version</code>.</p>
</li>
</ol>
<h4 id="heading-5-creating-the-production-archive">5. Creating the Production Archive</h4>
<p>Now that our application is built and we have a new version number, we need to package it up into a clean, production-ready archive.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">production</span> <span class="hljs-string">archive</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|</span>
    <span class="hljs-comment"># ... (rsync, composer install, cleanup, and zip commands) ...</span>
</code></pre>
<p>This step is quite long, but it's doing some very important things:</p>
<ul>
<li><p>It creates a temporary directory.</p>
</li>
<li><p>It uses <code>rsync</code> to copy all the application files, but it excludes all development-related files and directories like <code>.git</code>, <code>node_modules</code>, <code>vendor</code>, <code>tests</code>, etc. This ensures our archive is as small and clean as possible.</p>
</li>
<li><p>It then <code>cd</code>s into this temporary directory and runs <code>composer install --no-dev</code> again. This is crucial because it installs only the production dependencies inside our clean archive directory.</p>
</li>
<li><p>It performs some final cleanup, creates necessary directories, sets the correct permissions, and then creates a <code>.zip</code> archive named with the new version number (e.g., <a target="_blank" href="http://bill-organizer-1.2.4.zip"><code>bill-organizer-1.2.4.zip</code></a>).</p>
</li>
</ul>
<h4 id="heading-6-creating-the-github-release">6. Creating the GitHub Release</h4>
<p>This is the final and most rewarding part of the workflow.</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Delete</span> <span class="hljs-string">existing</span> <span class="hljs-string">draft</span> <span class="hljs-string">release</span> <span class="hljs-string">with</span> <span class="hljs-string">same</span> <span class="hljs-string">version</span> <span class="hljs-string">(if</span> <span class="hljs-string">any)</span>
  <span class="hljs-attr">env:</span>
    <span class="hljs-attr">GITHUB_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|
    # ... (gh release list and delete commands) ...
</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">Draft</span> <span class="hljs-string">Release</span>
  <span class="hljs-attr">env:</span>
    <span class="hljs-attr">GITHUB_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|</span>
    <span class="hljs-comment"># ... (gh release create command) ...</span>
</code></pre>
<p>We use the official GitHub CLI (<code>gh</code>) to interact with the GitHub API.</p>
<ul>
<li><p><strong>Delete Existing Draft:</strong> First, we have a neat little step that checks if there's already a draft release with the same version tag. If there is, it deletes it. This is useful if you have to re-run the workflow, as it prevents you from having multiple draft releases for the same version.</p>
</li>
<li><p><strong>Create Draft Release:</strong> This is the main event.</p>
<ul>
<li><p>We use <code>git log</code> to get all the commit messages since the last tag. This will be our automated changelog.</p>
</li>
<li><p>We then use <code>gh release create</code> to create a new draft release.</p>
</li>
<li><p>We pass the new version tag, the path to our <code>.zip</code> archive, and a title for the release.</p>
</li>
<li><p>The <code>--notes</code> flag is where we construct our detailed release notes. We include the new version number, the auto-generated changelog, installation instructions, and build information.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-7-uploading-build-artifacts">7. Uploading Build Artifacts</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">build</span> <span class="hljs-string">artifacts</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/upload-artifact@v4</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">bill-organizer-${{</span> <span class="hljs-string">steps.version.outputs.version_number</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">path:</span> <span class="hljs-string">bill-organizer-${{</span> <span class="hljs-string">steps.version.outputs.version_number</span> <span class="hljs-string">}}.zip</span>
    <span class="hljs-attr">retention-days:</span> <span class="hljs-number">30</span>
</code></pre>
<p>Finally, we use the <code>actions/upload-artifact@v4</code> action to upload our <code>.zip</code> archive as a build artifact. This is useful for debugging purposes and for keeping a record of all the builds.</p>
<h2 id="heading-the-result-a-seamless-release-experience">The Result: A Seamless Release Experience</h2>
<p>And that's it! With this workflow in place, my release process is now completely automated. Every time I push to <code>main</code>, a new, versioned, and production-ready release is created, complete with a changelog and a downloadable artifact.</p>
<p>This has been a game-changer for my development workflow. I no longer have to worry about the tedious and error-prone process of manual releases. I can simply push my code and be confident that a new release will be built and ready to go, allowing me to focus on what I love: building great software.</p>
<p>If you're still doing manual releases, I highly encourage you to explore GitHub Actions and build your own automated release pipeline. It's an investment that will pay for itself many times over in saved time, reduced stress, and more consistent, reliable releases.</p>
<blockquote>
<p>You can download the full <code>release.yml</code> file from <a target="_blank" href="https://raw.githubusercontent.com/4msar/bill-organizer/main/.github/workflows/release.yml">here</a>.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[🚀 Create a Folder Bookmarking System in Bash with goto and bookmark Commands]]></title><description><![CDATA[Tired of typing long paths or digging through cd history to jump to your commonly used directories? With a simple Bash tool, you can create named bookmarks for folders and jump to them instantly using goto.
In this article, you'll learn how to set up...]]></description><link>https://blog.msar.me/create-a-folder-bookmarking-system-in-bash-with-goto-and-bookmark-commands</link><guid isPermaLink="true">https://blog.msar.me/create-a-folder-bookmarking-system-in-bash-with-goto-and-bookmark-commands</guid><category><![CDATA[Bash]]></category><category><![CDATA[bash script]]></category><category><![CDATA[cli]]></category><category><![CDATA[cli tools]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Utilities]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 30 Jun 2025 14:58:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9jRG_Ym6GdQ/upload/1a20b46bb65d4b3d2edd6230563261f3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tired of typing long paths or digging through <code>cd</code> history to jump to your commonly used directories? With a simple Bash tool, you can create <strong>named bookmarks</strong> for folders and jump to them instantly using <code>goto</code>.</p>
<p>In this article, you'll learn how to set up:</p>
<ul>
<li><p>✅ <code>bookmark [name]</code> — Save the current directory under a friendly name</p>
</li>
<li><p>✅ <code>goto [name]</code> — Jump directly to a bookmarked folder (or interactively pick one)</p>
</li>
<li><p>✅ 🧠 Tab-autocomplete — Auto-suggest bookmark names with <code>&lt;TAB&gt;</code></p>
</li>
</ul>
<p>Let’s get started.</p>
<hr />
<h2 id="heading-1-add-bookmarking-script-to-your-shell">📁 1. Add Bookmarking Script to Your Shell</h2>
<p>Add the following code to your <code>~/.bashrc</code> (or <code>~/.zshrc</code> if you use Zsh):</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> ~/.bookmark
</code></pre>
<p>Now create a file in your home directory, <code>~/.bookmark</code> and put these code in there.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Bookmark storage file</span>
BOOKMARKS_FILE=<span class="hljs-string">"<span class="hljs-variable">$HOME</span>/.folder_bookmarks"</span>

<span class="hljs-comment"># Save current directory with a name</span>
<span class="hljs-function"><span class="hljs-title">bookmark</span></span>() {
    <span class="hljs-built_in">local</span> name=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>

    <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> -n <span class="hljs-string">"Enter bookmark name: "</span>
        <span class="hljs-built_in">read</span> name
    <span class="hljs-keyword">fi</span>

    <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmark name cannot be empty."</span>
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>

    mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>)</span>"</span>

    <span class="hljs-comment"># Remove any existing entry with the same name</span>
    grep -v <span class="hljs-string">"^<span class="hljs-variable">$name</span>|"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> 2&gt;/dev/null &gt; <span class="hljs-string">"<span class="hljs-variable">${BOOKMARKS_FILE}</span>.tmp"</span>
    mv <span class="hljs-string">"<span class="hljs-variable">${BOOKMARKS_FILE}</span>.tmp"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>

    <span class="hljs-comment"># Save the new bookmark</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$name</span>|<span class="hljs-variable">$PWD</span>"</span> &gt;&gt; <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmarked '<span class="hljs-variable">$PWD</span>' as '<span class="hljs-variable">$name</span>'"</span>
}

<span class="hljs-comment"># Navigate to a bookmarked directory</span>
<span class="hljs-function"><span class="hljs-title">goto</span></span>() {
    <span class="hljs-built_in">local</span> name=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>

    <span class="hljs-keyword">if</span> [ ! -f <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"No bookmarks found."</span>
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>

    <span class="hljs-built_in">local</span> dir

    <span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        dir=$(grep <span class="hljs-string">"^<span class="hljs-variable">$name</span>|"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> | cut -d<span class="hljs-string">'|'</span> -f2)
        <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span> ]; <span class="hljs-keyword">then</span>
            <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmark '<span class="hljs-variable">$name</span>' not found."</span>
            <span class="hljs-built_in">return</span> 1
        <span class="hljs-keyword">fi</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-comment"># Interactive prompt using fzf</span>
        <span class="hljs-built_in">local</span> selection
        selection=$(awk -F <span class="hljs-string">'|'</span> <span class="hljs-string">'{ printf "%s\t%s\n", $1, $2 }'</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> | fzf --prompt=<span class="hljs-string">"Goto bookmark: "</span> --with-nth=1)
        <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> ]; <span class="hljs-keyword">then</span>
            <span class="hljs-built_in">echo</span> <span class="hljs-string">"No selection made."</span>
            <span class="hljs-built_in">return</span> 1
        <span class="hljs-keyword">fi</span>
        dir=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> | cut -f2)
    <span class="hljs-keyword">fi</span>

    <span class="hljs-keyword">if</span> [ -d <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">cd</span> <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Directory does not exist: <span class="hljs-variable">$dir</span>"</span>
    <span class="hljs-keyword">fi</span>
}

<span class="hljs-comment"># Autocomplete function for goto</span>
<span class="hljs-function"><span class="hljs-title">_goto_complete</span></span>() {
    <span class="hljs-built_in">local</span> cur_word bookmarks
    cur_word=<span class="hljs-string">"<span class="hljs-variable">${COMP_WORDS[COMP_CWORD]}</span>"</span>
    <span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> ]; <span class="hljs-keyword">then</span>
        bookmarks=$(cut -d<span class="hljs-string">'|'</span> -f1 <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>)
        COMPREPLY=( $(compgen -W <span class="hljs-string">"<span class="hljs-variable">$bookmarks</span>"</span> -- <span class="hljs-string">"<span class="hljs-variable">$cur_word</span>"</span>) )
    <span class="hljs-keyword">fi</span>
}

<span class="hljs-comment"># Register autocomplete for goto</span>
complete -F _goto_complete goto
</code></pre>
<p>Download the file from <a target="_blank" href="https://gist.githubusercontent.com/4msar/a26356c809cf61e6d5899298049d565e/raw/345f819555a1becbad52c503fba2c4975208d2b7/.bookmark.sh">here</a>.</p>
<h2 id="heading-3-how-it-works-code-explanation">🧠 3. How It Works — Code Explanation</h2>
<p>Let’s break down how the <code>bookmark</code> and <code>goto</code> functions work under the hood, along with tab completion logic.</p>
<hr />
<h3 id="heading-bookmarksfilehomefolderbookmarks">📌 <code>BOOKMARKS_FILE="$HOME/.folder_bookmarks"</code></h3>
<p>This defines where all bookmarks will be saved — a simple text file where each line stores:</p>
<pre><code class="lang-bash">name|/absolute/path/to/folder
</code></pre>
<p>Example:</p>
<pre><code class="lang-bash">projectX|/home/user/code/projectX
work|/home/user/workspace
</code></pre>
<p>This file is used for reading and writing bookmark data.</p>
<hr />
<h3 id="heading-the-bookmark-function">💾 The <code>bookmark</code> Function</h3>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">bookmark</span></span>() {
    <span class="hljs-built_in">local</span> name=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>

    <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> -n <span class="hljs-string">"Enter bookmark name: "</span>
        <span class="hljs-built_in">read</span> name
    <span class="hljs-keyword">fi</span>
</code></pre>
<ul>
<li><p>If a name is passed as an argument, it's used.</p>
</li>
<li><p>If not, the user is prompted to enter one.</p>
</li>
</ul>
<pre><code class="lang-bash">    <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmark name cannot be empty."</span>
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>
</code></pre>
<ul>
<li>Ensures that an empty name isn’t saved.</li>
</ul>
<pre><code class="lang-bash">    mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>)</span>"</span>
</code></pre>
<ul>
<li>Makes sure the folder for the bookmarks file exists (mostly redundant but safe).</li>
</ul>
<pre><code class="lang-bash">    grep -v <span class="hljs-string">"^<span class="hljs-variable">$name</span>|"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> 2&gt;/dev/null &gt; <span class="hljs-string">"<span class="hljs-variable">${BOOKMARKS_FILE}</span>.tmp"</span>
    mv <span class="hljs-string">"<span class="hljs-variable">${BOOKMARKS_FILE}</span>.tmp"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>
</code></pre>
<ul>
<li>Removes any previous entry with the same name, so each bookmark name is unique.</li>
</ul>
<pre><code class="lang-bash">    <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$name</span>|<span class="hljs-variable">$PWD</span>"</span> &gt;&gt; <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmarked '<span class="hljs-variable">$PWD</span>' as '<span class="hljs-variable">$name</span>'"</span>
</code></pre>
<ul>
<li>Appends the new bookmark as <code>name|directory</code> to the file.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751295740329/302ea86c-2d1c-4c1e-8f47-6987c473c031.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-the-goto-function">🚀 The <code>goto</code> Function</h3>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">goto</span></span>() {
    <span class="hljs-built_in">local</span> name=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>

    <span class="hljs-keyword">if</span> [ ! -f <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"No bookmarks found."</span>
        <span class="hljs-built_in">return</span> 1
    <span class="hljs-keyword">fi</span>
</code></pre>
<ul>
<li>If the bookmarks file doesn’t exist, it aborts.</li>
</ul>
<h4 id="heading-option-1-name-is-given">📥 Option 1: Name is Given</h4>
<pre><code class="lang-bash">    <span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">$name</span>"</span> ]; <span class="hljs-keyword">then</span>
        dir=$(grep <span class="hljs-string">"^<span class="hljs-variable">$name</span>|"</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> | cut -d<span class="hljs-string">'|'</span> -f2)
        <span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span> ]; <span class="hljs-keyword">then</span>
            <span class="hljs-built_in">echo</span> <span class="hljs-string">"Bookmark '<span class="hljs-variable">$name</span>' not found."</span>
            <span class="hljs-built_in">return</span> 1
        <span class="hljs-keyword">fi</span>
</code></pre>
<ul>
<li><p>Searches the file for the bookmark and extracts the path.</p>
</li>
<li><p>If the name doesn’t match, shows an error.</p>
</li>
</ul>
<h4 id="heading-option-2-no-name-provided">📥 Option 2: No Name Provided</h4>
<pre><code class="lang-bash">    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">local</span> selection
        selection=$(awk -F <span class="hljs-string">'|'</span> <span class="hljs-string">'{ printf "%s\t%s\n", $1, $2 }'</span> <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span> | fzf --prompt=<span class="hljs-string">"Goto bookmark: "</span> --with-nth=1)
</code></pre>
<ul>
<li><p>Uses <code>fzf</code> to display an interactive list in the terminal.</p>
</li>
<li><p>Shows bookmarks in the format: <code>name /path</code>.</p>
</li>
</ul>
<pre><code class="lang-bash">        dir=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> | cut -f2)
</code></pre>
<ul>
<li>Extracts the selected path after the user chooses.</li>
</ul>
<h4 id="heading-navigate-to-the-folder">📂 Navigate to the Folder</h4>
<pre><code class="lang-bash">    <span class="hljs-keyword">if</span> [ -d <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span> ]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">cd</span> <span class="hljs-string">"<span class="hljs-variable">$dir</span>"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">echo</span> <span class="hljs-string">"Directory does not exist: <span class="hljs-variable">$dir</span>"</span>
    <span class="hljs-keyword">fi</span>
}
</code></pre>
<ul>
<li><p>Navigates to the directory if it still exists.</p>
</li>
<li><p>Shows an error if the path was deleted or moved.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751295771578/b38c616d-96e9-40c0-ae23-e9aeec3a4a41.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-tab-completion-for-goto">🔄 Tab Completion for <code>goto</code></h3>
<p>For Bash:</p>
<pre><code class="lang-bash"><span class="hljs-function"><span class="hljs-title">_goto_complete</span></span>() {
    <span class="hljs-built_in">local</span> cur_word bookmarks
    cur_word=<span class="hljs-string">"<span class="hljs-variable">${COMP_WORDS[COMP_CWORD]}</span>"</span>
    bookmarks=$(cut -d<span class="hljs-string">'|'</span> -f1 <span class="hljs-string">"<span class="hljs-variable">$BOOKMARKS_FILE</span>"</span>)
    COMPREPLY=( $(compgen -W <span class="hljs-string">"<span class="hljs-variable">$bookmarks</span>"</span> -- <span class="hljs-string">"<span class="hljs-variable">$cur_word</span>"</span>) )
}
complete -F _goto_complete goto
</code></pre>
<ul>
<li><p>Uses Bash’s <code>complete</code> system.</p>
</li>
<li><p>Pulls all bookmark names from the file and offers them as suggestions when the user presses <code>&lt;TAB&gt;</code>.</p>
</li>
</ul>
<p>For Zsh, a similar logic is used with <code>compctl</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751295820122/3413d282-a06a-4bbe-86e6-4e2c12bff7dc.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-summary">✅ Summary</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Component</td><td>Role</td></tr>
</thead>
<tbody>
<tr>
<td><code>bookmark</code></td><td>Saves the current folder with a custom name</td></tr>
<tr>
<td><code>goto</code></td><td>Navigates to a saved folder by name or interactive prompt</td></tr>
<tr>
<td><code>.folder_bookmarks</code></td><td>Stores bookmarks as `name</td></tr>
<tr>
<td><code>fzf</code></td><td>Provides fuzzy search UI when no bookmark name is given</td></tr>
<tr>
<td>Tab Completion</td><td>Enables <code>goto &lt;TAB&gt;</code> suggestions for saved bookmarks</td></tr>
</tbody>
</table>
</div><hr />
<p>This approach is simple, portable, and doesn't require any external frameworks — just Bash and <code>fzf</code>.</p>
<p>Would you like a downloadable <code>.sh</code> version or install script for easy sharing?</p>
<hr />
<h2 id="heading-3-requirements">⚙️ 3. Requirements</h2>
<p>This setup uses <a target="_blank" href="https://github.com/junegunn/fzf"><code>fzf</code></a> for fuzzy searching when <code>goto</code> is called without a name.</p>
<p>Install it using:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># macOS</span>
brew install fzf

<span class="hljs-comment"># Ubuntu/Debian</span>
sudo apt install fzf
</code></pre>
<p>Or install manually:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
</code></pre>
<hr />
<h2 id="heading-usage-examples">🚀 Usage Examples</h2>
<pre><code class="lang-bash">bookmark project-alpha    <span class="hljs-comment"># Save current directory as 'project-alpha'</span>
goto project-alpha        <span class="hljs-comment"># Jump to 'project-alpha'</span>

bookmark                  <span class="hljs-comment"># Prompts for a name</span>
goto                      <span class="hljs-comment"># Use fuzzy search to select one</span>
</code></pre>
<p>Hit <code>&lt;TAB&gt;</code> after typing <code>goto</code> to autocomplete available bookmarks!</p>
<hr />
<h2 id="heading-conclusion">📌 Conclusion</h2>
<p>With just a few lines of Bash and the power of <code>fzf</code>, you now have a fast, flexible, and friendly way to bookmark and navigate your filesystem. Whether you're managing multiple projects, deep folder hierarchies, or just want to speed up your workflow, this setup keeps your terminal navigation blazing fast.</p>
<p>Happy hacking! ⚡</p>
]]></content:encoded></item><item><title><![CDATA[Taming the Subscription Chaos: A Deep Dive into Bill Organizer]]></title><description><![CDATA[Early explore: visit the website(http://bills.msar.me/).
In an age where digital services are the lifeblood of our personal and professional lives, it's easy to lose track of the ever-growing list of recurring payments. From streaming services and so...]]></description><link>https://blog.msar.me/taming-the-subscription-chaos-a-deep-dive-into-bill-organizer</link><guid isPermaLink="true">https://blog.msar.me/taming-the-subscription-chaos-a-deep-dive-into-bill-organizer</guid><category><![CDATA[Bill Management]]></category><category><![CDATA[Shadcn vue]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[shadcn]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[learning]]></category><category><![CDATA[Build In Public]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Tue, 24 Jun 2025 18:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297829440/493f154a-82d0-4f80-9fd8-dcf1a7eb1c85.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Early explore: visit the <a target="_blank" href="http://bills.msar.me/">website</a>(<a target="_blank" href="http://bills.msar.me/">http://bills.msar.me/</a>).</p>
<p>In an age where digital services are the lifeblood of our personal and professional lives, it's easy to lose track of the ever-growing list of recurring payments. From streaming services and software subscriptions to monthly utilities, managing bills has become a complex and often stressful task. Missing a payment can lead to service interruptions or late fees, while forgetting to cancel an unused subscription can quietly drain your bank account.</p>
<p>This is the problem that <strong>Bill Organizer</strong>, an open-source application, sets out to solve. Built with a modern tech stack for performance and scalability, it offers a streamlined, self-hostable solution to take control of your financial obligations. This article will take you on a tour of the Bill Organizer project, exploring its architecture, how it works under the hood, and how you can become part of its journey through open-source contribution.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297187709/04fc775a-7841-476c-be35-18228d946bf1.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-is-bill-organizer">What is Bill Organizer?</h2>
<p>At its core, Bill Organizer is a user-friendly platform designed to help you manage all your bills and subscriptions in one centralized place. It provides a clear and intuitive interface to track due dates, payment amounts, and payment history, ensuring you never miss a beat.</p>
<p>The project is built on the philosophy that financial management tools should be accessible, private, and powerful. By being open-source, it offers complete transparency and gives users the freedom to host their own instance, ensuring their sensitive financial data remains under their control.</p>
<h3 id="heading-core-features">Core Features:</h3>
<ul>
<li><p><strong>Centralized Dashboard:</strong> Get an at-a-glance overview of your upcoming bills, recent payments, and spending trends.</p>
</li>
<li><p><strong>Bill &amp; Subscription Tracking:</strong> Easily add, edit, and manage all your recurring payments, from monthly subscriptions to annual renewals.</p>
</li>
<li><p><strong>Smart Categorization:</strong> Organize your bills into categories (e.g., "Entertainment," "Utilities," "Work Software") to better understand your spending habits.</p>
</li>
<li><p><strong>Payment History:</strong> Keep a log of all past payments for easy reference and financial auditing.</p>
</li>
<li><p><strong>Due Date Reminders:</strong> Receive timely notifications for upcoming bills, helping you avoid late fees and plan your finances accordingly.</p>
</li>
<li><p><strong>Currency Support:</strong> Manage bills in different currencies, making it suitable for users worldwide.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297466436/13433710-6ea3-40f5-8f73-4d776b45f610.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-look-under-the-hood-the-technology-stack">A Look Under the Hood: The Technology Stack</h2>
<p>Bill Organizer is crafted using a powerful combination of modern web technologies, chosen specifically for their robustness, developer experience, and performance. This "modern monolith" architecture combines the power of a traditional server-rendered application with the seamless, dynamic experience of a single-page application (SPA).</p>
<h3 id="heading-backend-the-power-of-laravel-12">Backend: The Power of Laravel 12</h3>
<p>The entire backend is powered by <strong>Laravel</strong>, the latest version of the popular PHP framework. Laravel is renowned for its elegant syntax, robust feature set, and strong security foundations.</p>
<ul>
<li><p><strong>Why Laravel?</strong> It provides a solid foundation with built-in features for routing, database management (through its Eloquent ORM), authentication, and more. This allows developers to focus on building core application features rather than reinventing the wheel.</p>
</li>
<li><p><strong>API &amp; Web Routes:</strong> The application uses a combination of web and API routes to handle requests. The core of the application's interactivity is managed through web routes that are tightly integrated with the frontend via Inertia.</p>
</li>
</ul>
<p>Here is a glimpse of how a route is defined in Laravel to fetch data for the frontend:</p>
<pre><code class="lang-php"><span class="hljs-comment">// routes/web.php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Http</span>\<span class="hljs-title">Controllers</span>\<span class="hljs-title">BillController</span>;

Route::get(<span class="hljs-string">'/bills'</span>, [BillController::class, <span class="hljs-string">'index'</span>])
    -&gt;name(<span class="hljs-string">'bills.index'</span>);
</code></pre>
<p>This simple line of code maps a URL to a controller method that fetches bill data and renders the corresponding Vue component, all in one go.</p>
<h3 id="heading-frontend-a-dynamic-experience-with-vuejs-3">Frontend: A Dynamic Experience with Vue.js 3</h3>
<p>The user interface is a highly interactive SPA built with <strong>Vue.js 3</strong>. Vue is a progressive JavaScript framework that is approachable, performant, and versatile.</p>
<ul>
<li><p><strong>Component-Based Architecture:</strong> The UI is broken down into reusable components (e.g., <code>BillTable</code>, <code>AddBillModal</code>, <code>DashboardChart</code>). This makes the codebase organized, maintainable, and easy to scale.</p>
</li>
<li><p><strong>Reactivity:</strong> Vue's reactivity system automatically updates the UI whenever the underlying data changes, providing a smooth and responsive user experience without manual DOM manipulation.</p>
</li>
</ul>
<p>Here's a simplified snippet of what a Vue component for displaying a list of bills might look like:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// resources/js/Pages/Bills/Index.vue</span>

&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { defineProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>;

<span class="hljs-comment">// Props are passed down from the Laravel controller</span>
<span class="hljs-keyword">const</span> props = defineProps({
  bills: <span class="hljs-built_in">Array</span>,
  totalDue: <span class="hljs-built_in">Number</span>,
});
&lt;/script&gt;

&lt;template&gt;
  &lt;h1&gt;My Bills&lt;/h1&gt;
  &lt;div v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"bill in props.bills"</span> :key=<span class="hljs-string">"bill.id"</span>&gt;
    &lt;p&gt;{{ bill.name }}: ${{ bill.amount }}&lt;/p&gt;
  &lt;/div&gt;
  &lt;strong&gt;Total Due: ${{ props.totalDue }}&lt;/strong&gt;
&lt;/template&gt;
</code></pre>
<h3 id="heading-the-bridge-inertiajs">The Bridge: Inertia.js</h3>
<p>The magic that connects the Laravel backend and Vue.js frontend is <strong>Inertia.js</strong>. It's not a framework itself, but a routing library that allows you to create modern, single-page Vue applications using classic server-side routing.</p>
<ul>
<li><strong>How it Works:</strong> When you navigate to a page, your Laravel application handles the request, fetches the necessary data, and instead of returning a JSON API response, it returns a full Vue component with the data passed as "props". This gives you the best of both worlds: the development speed of a monolith and the user experience of an SPA.</li>
</ul>
<h3 id="heading-development-and-tooling">Development and Tooling</h3>
<p>The project is committed to a high standard of code quality and a smooth developer experience, enforced by modern tooling:</p>
<ul>
<li><p><strong>Vite:</strong> A next-generation frontend build tool that provides lightning-fast hot module replacement (HMR) for a highly productive development workflow.</p>
</li>
<li><p><strong>TypeScript:</strong> The entire frontend codebase uses TypeScript, adding static type safety to prevent common errors and improve code maintainability.</p>
</li>
<li><p><strong>PHPStan &amp; Pint:</strong> For the backend, PHPStan is used for static analysis to catch bugs before they reach production, while Pint automatically formats the PHP code to ensure a consistent style.</p>
</li>
<li><p><strong>ESLint &amp; Prettier:</strong> These tools enforce a consistent coding style and catch potential issues in the TypeScript and Vue code.</p>
</li>
</ul>
<h2 id="heading-how-it-works-the-user-journey">How It Works: The User Journey</h2>
<p>Let's walk through a typical user flow to understand how these technologies come together.</p>
<p><strong>1. Viewing the Dashboard:</strong> When a user logs in, they are directed to the dashboard.</p>
<ul>
<li><p>The Laravel router catches the <code>/dashboard</code> request.</p>
</li>
<li><p>The <code>DashboardController</code> fetches key data: upcoming bills, total unpaid amount, and recent payments.</p>
</li>
<li><p>Laravel renders the <code>Dashboard.vue</code> component, passing the data as props via Inertia.</p>
</li>
<li><p>The Vue component displays the data, perhaps using charts (powered by a library like ApexCharts) and summary cards.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297325049/c1e31224-4aab-4105-b77d-5938da9199e7.png" alt class="image--center mx-auto" /></p>
<p><strong>2. Adding a New Bill:</strong> A user clicks the "Add Bill" button.</p>
<ul>
<li><p>This action likely opens a modal window (<code>AddBillModal.vue</code>) directly on the frontend.</p>
</li>
<li><p>The user fills out a form with details like the bill's name, amount, due date, and category. This form is managed by <code>VeeValidate</code> for real-time validation.</p>
</li>
<li><p>Upon submission, an API request is sent to a Laravel endpoint (e.g., <code>POST /bills</code>).</p>
</li>
<li><p>The <code>BillController</code> validates the incoming data and creates a new record in the <code>bills</code> database table.</p>
</li>
<li><p>After successfully creating the bill, Laravel redirects the user back to the bills list, and Inertia automatically fetches the updated data, causing the UI to update seamlessly.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297349186/eaef845b-a990-4aaf-bd50-12b48acbd128.png" alt class="image--center mx-auto" /></p>
<p><strong>3. Marking a Bill as Paid:</strong> A user wants to mark a bill as paid.</p>
<ul>
<li><p>They click a "Mark as Paid" button next to a bill in the list.</p>
</li>
<li><p>A <code>PATCH</code> or <code>PUT</code> request is sent to an endpoint like <code>/bills/{bill}/pay</code>.</p>
</li>
<li><p>The <code>BillController</code> updates the bill's status in the database.</p>
</li>
<li><p>The frontend immediately reflects this change, perhaps moving the bill to a "Paid" section or changing its visual style.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297362413/ce242562-7b94-4fc6-bd59-f36e23b74bae.png" alt class="image--center mx-auto" /></p>
<p><strong>4. Creating and Managing a Team:</strong> A user wants to manage bills with their family or business partners.</p>
<ul>
<li><p>The user navigates to the "Team Settings" area. This loads a <code>TeamSettings.vue</code> component.</p>
</li>
<li><p>They click "Create New Team" and enter a name, like "Household Bills" or "Startup Subscriptions."</p>
</li>
<li><p>On submission, a request hits the <code>TeamController</code> in Laravel, which creates a new team and assigns the user as the owner.</p>
</li>
<li><p>Now in the team management view, the user can invite others by entering their email addresses. An API call to <code>POST /teams/{team}/invitations</code> sends out invitations.</p>
</li>
<li><p>Invited users receive an email and an in-app notification. Accepting the invite adds them to the team.</p>
</li>
<li><p>The team owner can now share bills with the team and assign different roles (e.g., 'Admin', 'Member') to control who can add or modify bills, creating a collaborative financial management space.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751297566153/2b8918b9-a28d-4178-8e16-0712accacbc4.png" alt class="image--center mx-auto" /></p>
<p>To get more details of the application: browse the live link and use it. (<a target="_blank" href="http://bills.msar.me/">http://bills.msar.me/</a>)</p>
<h2 id="heading-open-for-contribution-lets-build-it-together">Open for Contribution: Let's Build It Together!</h2>
<p>Bill Organizer is more than just a tool; it's a community-driven project. Whether you are a seasoned developer, a student looking to build your portfolio, or someone passionate about open source, your contributions are welcome.</p>
<p>We believe that collaboration is the key to creating robust and meaningful software. By contributing, you can help fix bugs, add new features, improve the documentation, and shape the future of the project.</p>
<h3 id="heading-how-to-get-started">How to Get Started</h3>
<ol>
<li><p><strong>Explore the Repository:</strong> The first step is to visit the <a target="_blank" href="https://github.com/4msar/bill-organizer">GitHub repository</a>. Read the <a target="_blank" href="http://README.md"><code>README.md</code></a> file to understand the project setup and installation instructions.</p>
</li>
<li><p><strong>Find an Issue:</strong> Check out the "Issues" tab. We use labels like <code>good first issue</code> and <code>help wanted</code> to highlight tasks that are perfect for new contributors.</p>
</li>
<li><p><strong>Set Up Your Environment:</strong> Follow the local development setup guide. The project uses Laravel Sail and Yarn to make this process as smooth as possible. With a few simple commands, you'll have a fully functional development environment running on your machine.</p>
</li>
<li><p><strong>Create a Pull Request:</strong> Once you've made your changes, submit a pull request (PR). Be sure to describe the changes you've made and reference the issue you're solving. Your PR will be reviewed by the maintainers, who will provide feedback and guide you through the process.</p>
</li>
</ol>
<h3 id="heading-what-we-need">What We Need</h3>
<p>We are looking for help in all areas, including:</p>
<ul>
<li><p><strong>Feature Development:</strong> Have an idea for a new feature? Propose it in an issue and help us build it!</p>
</li>
<li><p><strong>Bug Fixes:</strong> Help us improve the stability of the application by tackling existing bugs.</p>
</li>
<li><p><strong>Refactoring &amp; Performance:</strong> Improve the codebase by refactoring or optimizing performance-critical sections.</p>
</li>
<li><p><strong>Documentation:</strong> Good documentation is crucial. Help us improve our guides and inline code comments.</p>
</li>
<li><p><strong>Testing:</strong> Writing automated tests is essential for long-term stability. We use Pest for our PHP tests.</p>
</li>
</ul>
<p>Join us in building the best open-source tool for managing personal finances. Your skills and ideas can make a real impact. Let's tame the chaos of bills, together!</p>
]]></content:encoded></item><item><title><![CDATA[Intro: PHP Package development]]></title><description><![CDATA[Introduction
Laravel is one of the most popular PHP frameworks, known for its elegant syntax and powerful tools that simplify web development. One of the strengths of Laravel is its flexibility and extensibility, allowing developers to create custom ...]]></description><link>https://blog.msar.me/intro-php-package-development</link><guid isPermaLink="true">https://blog.msar.me/intro-php-package-development</guid><category><![CDATA[php package]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Package Development]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Laravel Packages]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 02 Dec 2024 04:39:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/IudBpcHKV3k/upload/6cd6c1603885d4904b7d4a4441dbcc1d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Introduction</strong></p>
<p>Laravel is one of the most popular PHP frameworks, known for its elegant syntax and powerful tools that simplify web development. One of the strengths of Laravel is its flexibility and extensibility, allowing developers to create custom packages to extend the functionality of their applications. In this article, we'll explore the steps involved in creating a PHP package in Laravel, complete with examples and references.</p>
<hr />
<p><strong>Why Create a Laravel Package?</strong></p>
<p>Creating a Laravel package is beneficial when you have functionality that you want to reuse across multiple projects. Instead of duplicating code, you can encapsulate it within a package that can be easily installed and maintained.</p>
<p>Some common use cases for Laravel packages include:</p>
<ul>
<li><p><strong>Custom authentication systems</strong></p>
</li>
<li><p><strong>Reusable UI components</strong></p>
</li>
<li><p><strong>API integrations</strong></p>
</li>
<li><p><strong>Command-line tools</strong></p>
</li>
</ul>
<hr />
<p><strong>Step 1: Setting Up the Package</strong></p>
<p>To begin, you'll need to create a directory for your package. Laravel suggests placing your packages within the <code>packages</code> directory in the root of your Laravel project.</p>
<pre><code class="lang-bash">mkdir packages/YourVendorName/YourPackageName
<span class="hljs-built_in">cd</span> packages/YourVendorName/YourPackageName
</code></pre>
<p>Here, <code>YourVendorName</code> represents the vendor or author of the package (usually your or your company’s name), and <code>YourPackageName</code> is the name of the package.</p>
<p>Next, you need to create the <code>composer.json</code> file, which defines the package's dependencies and metadata.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"your-vendor-name/your-package-name"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"A short description of your package"</span>,
    <span class="hljs-attr">"authors"</span>: [
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Your Name"</span>,
            <span class="hljs-attr">"email"</span>: <span class="hljs-string">"your-email@example.com"</span>
        }
    ],
    <span class="hljs-attr">"autoload"</span>: {
        <span class="hljs-attr">"psr-4"</span>: {
            <span class="hljs-attr">"YourVendorName\\YourPackageName\\"</span>: <span class="hljs-string">"src/"</span>
        }
    }
}
</code></pre>
<p>This <code>composer.json</code> file tells Composer (PHP’s dependency manager) how to autoload your package and its dependencies.</p>
<hr />
<p><strong>Step 2: Developing the Package</strong></p>
<p>Inside the <code>src</code> directory, you can start developing your package. Let’s say you want to create a package that adds a custom greeting service to your Laravel application.</p>
<p>First, create a service provider. Service providers are the central place of configuration in a Laravel application.</p>
<pre><code class="lang-php"><span class="hljs-comment">// src/GreetingServiceProvider.php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">YourVendorName</span>\<span class="hljs-title">YourPackageName</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">ServiceProvider</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GreetingServiceProvider</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ServiceProvider</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;app-&gt;singleton(<span class="hljs-string">'greeting'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$app</span>) </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> GreetingService();
        });
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment">// Bootstrapping package functionalities (routes, views, etc.)</span>
    }
}
</code></pre>
<p>Next, create the <code>GreetingService</code> class.</p>
<pre><code class="lang-php"><span class="hljs-comment">// src/GreetingService.php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">YourVendorName</span>\<span class="hljs-title">YourPackageName</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GreetingService</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greet</span>(<span class="hljs-params">$name</span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, <span class="hljs-subst">$name</span>!"</span>;
    }
}
</code></pre>
<p>The service provider registers the <code>GreetingService</code> so that it can be easily accessed throughout your Laravel application.</p>
<hr />
<p><strong>Step 3: Registering the Package</strong></p>
<p>To make Laravel aware of your package, you need to add the service provider to the <code>config/app.php</code> file in the <code>providers</code> array.</p>
<pre><code class="lang-php"><span class="hljs-string">'providers'</span> =&gt; [
    <span class="hljs-comment">// Other Service Providers</span>

    YourVendorName\YourPackageName\GreetingServiceProvider::class,
],
</code></pre>
<p>Now, you can use your package within the Laravel application:</p>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/greet/{name}'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$name</span>) </span>{
    <span class="hljs-keyword">return</span> app(<span class="hljs-string">'greeting'</span>)-&gt;greet($name);
});
</code></pre>
<hr />
<p><strong>Step 4: Publishing Package Assets (Optional)</strong></p>
<p>If your package includes configuration files, views, or other assets that need to be published to the main Laravel project, you can use the <code>publishes</code> method in your service provider.</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;publishes([
        <span class="hljs-keyword">__DIR__</span>.<span class="hljs-string">'/path/to/config/greeting.php'</span> =&gt; config_path(<span class="hljs-string">'greeting.php'</span>),
    ]);
}
</code></pre>
<hr />
<p><strong>Step 5: Releasing the Package</strong></p>
<p>Once your package is complete, you can version it and share it with others. You can publish it on <a target="_blank" href="https://packagist.org/">Packagist</a>, the default package repository for Composer. First, create a Git repository for your package and push your code.</p>
<p>Then, tag a release:</p>
<pre><code class="lang-bash">git tag -a v1.0.0 -m <span class="hljs-string">"Initial release"</span>
git push origin v1.0.0
</code></pre>
<p>Finally, submit your package to Packagist by linking it to your GitHub repository.</p>
<hr />
<p><strong>Conclusion</strong></p>
<p>Creating a Laravel package is a great way to modularize your code and share it with the community. By following the steps above, you can develop, register, and release a package that adds reusable functionality to any Laravel project.</p>
<p>For further reading and advanced features, such as testing your package and setting up continuous integration, consider the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://laravel.com/docs/packages">Laravel Package Development Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://getcomposer.org/doc/">Composer Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.php-fig.org/psr/psr-4/">PSR-4 Autoloading Standard</a></p>
</li>
</ul>
<hr />
<p>By following these steps and best practices, you'll be well on your way to developing robust and reusable packages for your Laravel applications. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Zustand: A Lightweight State Management Library for React]]></title><description><![CDATA[State management is a crucial aspect of building robust and scalable React applications. While there are numerous state management libraries available, Zustand has emerged as a lightweight and flexible alternative that provides a simple yet powerful ...]]></description><link>https://blog.msar.me/understanding-zustand-a-lightweight-state-management-library-for-react</link><guid isPermaLink="true">https://blog.msar.me/understanding-zustand-a-lightweight-state-management-library-for-react</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[State Management ]]></category><category><![CDATA[React]]></category><category><![CDATA[zustand]]></category><category><![CDATA[Global State Management]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[Javascript library]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Tue, 16 Jul 2024 11:16:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721129349514/b51c619e-96e2-42fe-b1d7-4d7304dbf420.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>State management is a crucial aspect of building robust and scalable React applications. While there are numerous state management libraries available, Zustand has emerged as a lightweight and flexible alternative that provides a simple yet powerful way to manage state in React applications. This article delves into what Zustand is, its use cases, and some examples of its promising APIs, all in TypeScript.</p>
<h3 id="heading-what-is-zustand">What is Zustand?</h3>
<p><a target="_blank" href="https://zustand-demo.pmnd.rs/">Zustand</a> is a small, fast, and scalable state management library for React. Unlike more complex libraries such as Redux, Zustand is designed to be minimalistic, with an API that's easy to use and integrate into any React application. It uses hooks to manage state, making it a perfect fit for modern React applications that leverage the power of hooks for state and side-effect management.</p>
<h3 id="heading-key-features-of-zustand">Key Features of Zustand</h3>
<ul>
<li><p><strong>Minimalistic and Lightweight:</strong> Zustand has a small bundle size and minimal API surface, making it easy to learn and use.</p>
</li>
<li><p><strong>No Boilerplate:</strong> It eliminates the need for boilerplate code, allowing developers to focus on application logic rather than wiring up actions and reducers.</p>
</li>
<li><p><strong>Performance:</strong> Zustand is optimized for performance, ensuring that state updates are efficient and don't cause unnecessary re-renders.</p>
</li>
<li><p><strong>Flexible and Scalable:</strong> It can be used for both simple and complex state management needs, making it suitable for a wide range of applications.</p>
</li>
</ul>
<h3 id="heading-use-cases-for-zustand">Use Cases for Zustand</h3>
<p>Zustand can be used in various scenarios where state management is required. Here are a few common use cases:</p>
<ol>
<li><p><strong>Global State Management:</strong> Managing global state across the entire application, such as user authentication, theme settings, and application configuration.</p>
</li>
<li><p><strong>Component State Management:</strong> Handling state that is shared between multiple components, such as form inputs, filters, and UI state.</p>
</li>
<li><p><strong>Asynchronous State Management:</strong> Managing state that depends on asynchronous operations, such as fetching data from an API and handling loading and error states.</p>
</li>
</ol>
<h3 id="heading-getting-started-with-zustand">Getting Started with Zustand</h3>
<p>To get started with Zustand, you need to install it in your React project:</p>
<pre><code class="lang-bash">npm install zustand
<span class="hljs-comment"># or</span>
yarn add zustand
</code></pre>
<h3 id="heading-basic-example">Basic Example</h3>
<p>Let's start with a basic example of using Zustand to manage the state of a counter:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>;

<span class="hljs-keyword">interface</span> State {
  count: <span class="hljs-built_in">number</span>;
  increment: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
  decrement: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">const</span> useStore = create&lt;State&gt;(<span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
  count: <span class="hljs-number">0</span>,
  increment: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count + <span class="hljs-number">1</span> })),
  decrement: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count - <span class="hljs-number">1</span> })),
}));

<span class="hljs-keyword">const</span> Counter: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { count, increment, decrement } = useStore();
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;{count}&lt;/h1&gt;
      &lt;button onClick={increment}&gt;Increment&lt;/button&gt;
      &lt;button onClick={decrement}&gt;Decrement&lt;/button&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter;
</code></pre>
<p>In this example, we define a store using the <code>create</code> function from Zustand. The store has a state object with a <code>count</code> property and two actions: <code>increment</code> and <code>decrement</code>. These actions update the state using the <code>set</code> function. The <code>Counter</code> component uses the <code>useStore</code> hook to access the state and actions, allowing it to display and modify the counter value.</p>
<h3 id="heading-advanced-example-asynchronous-state-management">Advanced Example: Asynchronous State Management</h3>
<p>Zustand can also handle asynchronous operations seamlessly. Here's an example of fetching data from an API:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>;

<span class="hljs-keyword">interface</span> State {
  data: <span class="hljs-built_in">any</span>;
  loading: <span class="hljs-built_in">boolean</span>;
  error: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
  fetchData: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;;
}

<span class="hljs-keyword">const</span> useStore = create&lt;State&gt;(<span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
  data: <span class="hljs-literal">null</span>,
  loading: <span class="hljs-literal">false</span>,
  error: <span class="hljs-literal">null</span>,
  fetchData: <span class="hljs-keyword">async</span> () =&gt; {
    set({ loading: <span class="hljs-literal">true</span>, error: <span class="hljs-literal">null</span> });
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);
      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
      set({ data: result, loading: <span class="hljs-literal">false</span> });
    } <span class="hljs-keyword">catch</span> (error) {
      set({ error: error.message, loading: <span class="hljs-literal">false</span> });
    }
  },
}));

<span class="hljs-keyword">const</span> DataFetcher: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { data, loading, error, fetchData } = useStore();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;button onClick={fetchData}&gt;Fetch Data&lt;/button&gt;
      {loading &amp;&amp; &lt;p&gt;Loading...&lt;/p&gt;}
      {error &amp;&amp; &lt;p&gt;<span class="hljs-built_in">Error</span>: {error}&lt;/p&gt;}
      {data &amp;&amp; &lt;pre&gt;{<span class="hljs-built_in">JSON</span>.stringify(data, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)}&lt;/pre&gt;}
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DataFetcher;
</code></pre>
<p>In this example, the store has additional state properties (<code>data</code>, <code>loading</code>, and <code>error</code>) and an asynchronous action (<code>fetchData</code>) that fetches data from an API. The <code>DataFetcher</code> component uses the <code>useStore</code> hook to access the state and action, allowing it to initiate the fetch operation and display the results.</p>
<h3 id="heading-promising-apis-in-zustand">Promising APIs in Zustand</h3>
<p>Zustand offers several promising APIs that enhance its functionality:</p>
<ol>
<li><strong>Selectors:</strong> Zustand supports selectors for efficient state selection, allowing components to subscribe to specific parts of the state.</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> counter = <span class="hljs-function">() =&gt;</span> useStore(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.count);
<span class="hljs-keyword">const</span> setCounter = <span class="hljs-function">() =&gt;</span> useStore(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.setCount);
</code></pre>
<ol start="2">
<li><strong>Middleware:</strong> Zustand allows middleware to be added to stores for advanced use cases such as logging, persisting state, and handling side effects.</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>;
<span class="hljs-keyword">import</span> { persist } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand/middleware'</span>;

<span class="hljs-keyword">const</span> useStore = create&lt;State&gt;(
  persist(
    <span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
      count: <span class="hljs-number">0</span>,
      increment: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count + <span class="hljs-number">1</span> })),
      decrement: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count - <span class="hljs-number">1</span> })),
    }),
    { name: <span class="hljs-string">'counter'</span> }
  )
);
</code></pre>
<ol start="3">
<li><strong>Computed State:</strong> Zustand supports derived state, enabling the creation of computed properties based on the store's state.</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> doubleCount = <span class="hljs-function">() =&gt;</span> useStore(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.count * <span class="hljs-number">2</span>);
</code></pre>
<ol start="4">
<li><strong>Devtools Integration:</strong> Zustand integrates with Redux DevTools for better debugging and state inspection.</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { devtools } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand/middleware'</span>;

<span class="hljs-keyword">const</span> useStore = create&lt;State&gt;(
  devtools(<span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
    count: <span class="hljs-number">0</span>,
    increment: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count + <span class="hljs-number">1</span> })),
    decrement: <span class="hljs-function">() =&gt;</span> set(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({ count: state.count - <span class="hljs-number">1</span> })),
  }))
);
</code></pre>
<h2 id="heading-real-life-example-with-slice-pattern">Real life example with slice pattern</h2>
<p>Using the slice pattern with Zustand allows you to modularize and organize your state management logic into smaller, reusable pieces. This pattern is particularly useful for larger applications where you want to maintain a clear separation of concerns. Below, we'll enhance the contact form example by using the slice pattern.</p>
<h3 id="heading-setting-up-the-zustand-store-with-slices">Setting Up the Zustand Store with Slices</h3>
<p>First, create slices for the contact form state. Create a file named <code>contactStore.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { create, <span class="hljs-keyword">type</span> StateCreator } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>;

<span class="hljs-keyword">interface</span> ContactFormSlice {
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
  subject: <span class="hljs-built_in">string</span>;
  message: <span class="hljs-built_in">string</span>;
  setName: <span class="hljs-function">(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
  setEmail: <span class="hljs-function">(<span class="hljs-params">email: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
  setSubject: <span class="hljs-function">(<span class="hljs-params">subject: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
  setMessage: <span class="hljs-function">(<span class="hljs-params">message: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
  resetForm: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">const</span> createContactFormSlice: StateCreator&lt;ContactFormSlice&gt; = <span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
  name: <span class="hljs-string">''</span>,
  email: <span class="hljs-string">''</span>,
  subject: <span class="hljs-string">''</span>,
  message: <span class="hljs-string">''</span>,
  setName: <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> set({ name }),
  setEmail: <span class="hljs-function">(<span class="hljs-params">email</span>) =&gt;</span> set({ email }),
  setSubject: <span class="hljs-function">(<span class="hljs-params">subject</span>) =&gt;</span> set({ subject }),
  setMessage: <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> set({ message }),
  resetForm: <span class="hljs-function">() =&gt;</span> set({
    name: <span class="hljs-string">''</span>,
    email: <span class="hljs-string">''</span>,
    subject: <span class="hljs-string">''</span>,
    message: <span class="hljs-string">''</span>,
  }),
});

<span class="hljs-keyword">interface</span> Store <span class="hljs-keyword">extends</span> ContactFormSlice {}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useStore = create&lt;Store&gt;(<span class="hljs-function">(<span class="hljs-params">set</span>) =&gt;</span> ({
  ...createContactFormSlice(set),
}));
</code></pre>
<h3 id="heading-creating-the-contact-form-component">Creating the Contact Form Component</h3>
<p>Now, create a page or component for the contact form. Here’s an example using a functional component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'../store/contactStore'</span>;
<span class="hljs-keyword">import</span> { FormEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ContactForm = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { name, email, subject, message, setName, setEmail, setSubject, setMessage, resetForm } = useStore();

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e: FormEvent</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-comment">// Here, you can handle the form submission, e.g., send the data to an API</span>
    <span class="hljs-built_in">console</span>.log({ name, email, subject, message });
    resetForm();
  };

  <span class="hljs-keyword">return</span> (
    &lt;form onSubmit={handleSubmit}&gt;
      &lt;div&gt;
        &lt;label htmlFor=<span class="hljs-string">"name"</span>&gt;Name:&lt;/label&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          id=<span class="hljs-string">"name"</span>
          value={name}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setName(e.target.value)}
          required
        /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label htmlFor=<span class="hljs-string">"email"</span>&gt;Email:&lt;/label&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span>
          id=<span class="hljs-string">"email"</span>
          value={email}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value)}
          required
        /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label htmlFor=<span class="hljs-string">"subject"</span>&gt;Subject:&lt;/label&gt;
        &lt;input
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          id=<span class="hljs-string">"subject"</span>
          value={subject}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setSubject(e.target.value)}
          required
        /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label htmlFor=<span class="hljs-string">"message"</span>&gt;Message:&lt;/label&gt;
        &lt;textarea
          id=<span class="hljs-string">"message"</span>
          value={message}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setMessage(e.target.value)}
          required
        /&gt;
      &lt;/div&gt;
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ContactForm;
</code></pre>
<h3 id="heading-using-the-contact-form">Using the Contact form</h3>
<p>You can now integrate the <code>ContactForm</code> component into any page in your application. For example, if you want to display it on the home page, you can modify <code>pages/home.tsx</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> ContactForm <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/ContactForm'</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Contact Us&lt;/h1&gt;
      &lt;ContactForm /&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Using the slice pattern with Zustand, we have modularized the state management for a contact form in a React application. This approach helps in maintaining a clean and organized codebase, especially as the application grows. By defining slices and combining them into a single store, you can easily manage different parts of your application state in a scalable manner.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Zustand is a powerful and flexible state management library that offers a minimalistic API, making it an excellent choice for both simple and complex React applications. Its lightweight nature, combined with features like selectors, middleware, computed state, and devtools integration, makes it a compelling alternative to more heavyweight state management solutions. Whether you're building a small project or a large-scale application, Zustand provides the tools you need to manage state efficiently and effectively.</p>
<p>For more information visit there documentation from <a target="_blank" href="https://docs.pmnd.rs/zustand/getting-started/introduction">here.</a> And still if you need help then let discuss and explore.</p>
]]></content:encoded></item><item><title><![CDATA[Database Indexing - Why it's matter?]]></title><description><![CDATA[Database indexing is crucial in Laravel application development for several reasons:

Performance Improvement:

Faster Query Execution: Indexes allow the database to find and retrieve specific rows much faster than it could without them. This signifi...]]></description><link>https://blog.msar.me/database-indexing-why-its-matter</link><guid isPermaLink="true">https://blog.msar.me/database-indexing-why-its-matter</guid><category><![CDATA[Database Improvement]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Databases]]></category><category><![CDATA[database indexing]]></category><category><![CDATA[Database Performance Optimization Techniques, ]]></category><category><![CDATA[Improve Database Performance,]]></category><category><![CDATA[PHP]]></category><category><![CDATA[SQL]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[database design]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Thu, 27 Jun 2024 12:32:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/lRoX0shwjUQ/upload/e602ef2aa20ea9f83f1c631009ca9725.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Database indexing is crucial in Laravel application development for several reasons:</p>
<ol>
<li><p><strong>Performance Improvement</strong>:</p>
<ul>
<li><p><strong>Faster Query Execution</strong>: Indexes allow the database to find and retrieve specific rows much faster than it could without them. This significantly reduces the time it takes to execute queries, especially on large datasets.</p>
</li>
<li><p><strong>Efficient Data Retrieval</strong>: With indexes, the database can quickly locate the data without scanning the entire table, resulting in quicker response times for SELECT queries.</p>
</li>
</ul>
</li>
<li><p><strong>Optimized Resource Usage</strong>:</p>
<ul>
<li><p><strong>Reduced CPU and Memory Usage</strong>: Since indexes make data retrieval more efficient, they help reduce the load on the CPU and memory. This optimization is crucial for maintaining the overall performance of the application, particularly under heavy load.</p>
</li>
<li><p><strong>Lower I/O Operations</strong>: Indexes decrease the number of disk I/O operations required to retrieve data, which is beneficial for improving performance in environments where disk speed is a bottleneck.</p>
</li>
</ul>
</li>
<li><p><strong>Enhanced User Experience</strong>:</p>
<ul>
<li><p><strong>Responsive Applications</strong>: Fast data retrieval directly impacts the responsiveness of an application. Users experience quicker load times and smoother interactions, which is essential for maintaining user satisfaction and engagement.</p>
</li>
<li><p><strong>Scalability</strong>: Efficient indexing allows an application to scale better. As the dataset grows, well-indexed databases can handle increased traffic and larger volumes of data without significant performance degradation.</p>
</li>
</ul>
</li>
<li><p><strong>Supporting Complex Queries</strong>:</p>
<ul>
<li><p><strong>Efficient Sorting and Filtering</strong>: Indexes are beneficial for operations that involve sorting and filtering data. They help optimize ORDER BY and WHERE clauses, making these operations more efficient.</p>
</li>
<li><p><strong>Joins Optimization</strong>: Indexes can significantly speed up JOIN operations by quickly locating the matching rows in related tables, thus improving the performance of complex queries involving multiple tables.</p>
</li>
</ul>
</li>
<li><p><strong>Best Practices and Maintenance</strong>:</p>
<ul>
<li><p><strong>Index Management</strong>: Laravel’s Eloquent ORM provides methods to create and manage indexes easily. Properly managing indexes (adding, updating, or removing them as needed) ensures the database remains optimized.</p>
</li>
<li><p><strong>Avoiding Over-Indexing</strong>: While indexes are beneficial, having too many can lead to performance issues during INSERT, UPDATE, and DELETE operations. It’s important to balance the number of indexes to maintain optimal performance for both read and write operations.</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-improve-database-with-proper-indexing">Improve database with proper indexing</h2>
<p>Improving your database with proper indexing involves understanding the specific needs of your application and the queries that are being executed most frequently. Here are steps and best practices to guide you through the process:</p>
<h3 id="heading-1-analyze-your-queries">1. Analyze Your Queries</h3>
<p>Identify the queries that are run most frequently and those that have the highest impact on performance. Use tools and techniques like query logs, profiling, and monitoring tools to gather this information.</p>
<h3 id="heading-2-identify-candidates-for-indexing">2. Identify Candidates for Indexing</h3>
<p>Focus on the following types of columns when considering which to index:</p>
<ul>
<li><p><strong>Primary Keys</strong>: These are often indexed automatically by the database.</p>
</li>
<li><p><strong>Foreign Keys</strong>: Indexing foreign keys can speed up joins and improve referential integrity checks.</p>
</li>
<li><p><strong>Columns in WHERE Clauses</strong>: Columns frequently used in WHERE clauses can benefit significantly from indexing.</p>
</li>
<li><p><strong>Columns in JOIN Conditions</strong>: Columns that are used in JOIN operations.</p>
</li>
<li><p><strong>Columns in ORDER BY and GROUP BY Clauses</strong>: Indexing these can speed up sorting and grouping operations.</p>
</li>
<li><p><strong>Columns used in Aggregate Functions</strong>: Such as COUNT(), AVG(), SUM().</p>
</li>
</ul>
<h3 id="heading-3-use-the-right-type-of-index">3. Use the Right Type of Index</h3>
<ul>
<li><p><strong>Single-Column Index</strong>: Simple and useful for columns that are often queried alone.</p>
</li>
<li><p><strong>Composite Index</strong>: Useful for queries that filter or sort by multiple columns. The order of columns in the index should match the order of columns in your queries.</p>
</li>
<li><p><strong>Unique Index</strong>: Ensures that all values in the index are unique. This is automatically created for primary keys.</p>
</li>
</ul>
<h3 id="heading-4-avoid-over-indexing">4. Avoid Over-Indexing</h3>
<p>While indexes can speed up read operations, they can slow down write operations (INSERT, UPDATE, DELETE). Avoid creating unnecessary indexes that won’t be used frequently.</p>
<h3 id="heading-5-use-indexes-for-full-text-search">5. Use Indexes for Full-Text Search</h3>
<p>For columns that store large text values and need full-text search capabilities, consider using full-text indexes.</p>
<h3 id="heading-6-regular-maintenance">6. Regular Maintenance</h3>
<ul>
<li><p><strong>Monitor and Analyze Index Usage</strong>: Regularly check which indexes are being used and which are not. Remove unused indexes.</p>
</li>
<li><p><strong>Rebuild and Reorganize Indexes</strong>: Over time, indexes can become fragmented. Periodically rebuild or reorganize them to maintain performance.</p>
</li>
</ul>
<h3 id="heading-monitoring-and-tuning-indexes">Monitoring and Tuning Indexes</h3>
<ol>
<li><p><strong>Use Database-Specific Tools</strong>:</p>
<ul>
<li><p><strong>MySQL</strong>: <code>EXPLAIN</code>, <code>SHOW INDEXES</code>, and the slow query log.</p>
</li>
<li><p><strong>PostgreSQL</strong>: <code>EXPLAIN ANALYZE</code>, <code>pg_stat_user_indexes</code>, and <code>pg_stat_all_indexes</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Use Laravel Debugging Tools</strong>:</p>
<ul>
<li><p><strong>Laravel Telescope</strong>: Provides insights into queries and their execution times.</p>
</li>
<li><p><strong>Laravel Debugbar</strong>: Offers a comprehensive view of the executed queries during a request.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-implementation-in-laravel">Implementation in Laravel</h3>
<p>In Laravel, you can create indexes using migrations, which makes the process straightforward and maintains consistency in your database schema. Here are some examples:</p>
<ul>
<li><p><strong>Creating an Index</strong>:</p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index(<span class="hljs-string">'email'</span>);
  });
</code></pre>
</li>
<li><p><strong>Creating a Unique Index</strong>:</p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;unique(<span class="hljs-string">'email'</span>);
  });
</code></pre>
</li>
<li><p><strong>Creating a Composite Index</strong>:</p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index([<span class="hljs-string">'first_name'</span>, <span class="hljs-string">'last_name'</span>]);
  });
  <span class="hljs-comment">// another example</span>
  Schema::table(<span class="hljs-string">'orders'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index([<span class="hljs-string">'user_id'</span>, <span class="hljs-string">'product_id'</span>]);
  });
</code></pre>
</li>
<li><p><strong>Dropping an Index</strong></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;dropIndex([<span class="hljs-string">'email'</span>]); <span class="hljs-comment">// drops index 'users_email_index'</span>
  });
</code></pre>
</li>
<li><p><strong>Full-Text Index (if supported by your database)</strong></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'posts'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;fullText(<span class="hljs-string">'content'</span>);
  });
</code></pre>
</li>
</ul>
<h3 id="heading-example-improving-indexing-strategy">Example: Improving Indexing Strategy</h3>
<p>Consider we have an e-commerce application, Now let's make some improvement of this application Database.</p>
<p><em>Improving the database for an e-commerce Laravel application involves implementing a well-thought-out indexing strategy and optimizing database design. Here are some practical examples to illustrate this:</em></p>
<h3 id="heading-1-indexing-key-columns">1. <strong>Indexing Key Columns</strong></h3>
<h4 id="heading-products-table">Products Table</h4>
<ul>
<li><p><strong>Query</strong>: Retrieve products by category.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> category_id = <span class="hljs-number">1</span>;
</code></pre>
<p>  <strong>Index</strong>: <code>category_id</code></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'products'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index(<span class="hljs-string">'category_id'</span>);
  });
</code></pre>
</li>
</ul>
<h4 id="heading-orders-table">Orders Table</h4>
<ul>
<li><p><strong>Query</strong>: Fetch all orders for a specific user, sorted by date.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> orders <span class="hljs-keyword">WHERE</span> user_id = <span class="hljs-number">1</span> <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> created_at <span class="hljs-keyword">DESC</span>;
</code></pre>
<p>  <strong>Index</strong>: Composite index on <code>user_id</code> and <code>created_at</code></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'orders'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index([<span class="hljs-string">'user_id'</span>, <span class="hljs-string">'created_at'</span>]);
  });
</code></pre>
</li>
</ul>
<h4 id="heading-users-table">Users Table</h4>
<ul>
<li><p><strong>Query</strong>: Find a user by email.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> email = <span class="hljs-string">'example@example.com'</span>;
</code></pre>
<p>  <strong>Index</strong>: <code>email</code></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;unique(<span class="hljs-string">'email'</span>);
  });
</code></pre>
</li>
</ul>
<h3 id="heading-2-improving-full-text-search">2. <strong>Improving Full-Text Search</strong></h3>
<h4 id="heading-products-table-1">Products Table</h4>
<ul>
<li><p><strong>Query</strong>: Search products by name or description.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">MATCH</span>(<span class="hljs-keyword">name</span>, description) AGAINST(<span class="hljs-string">'laptop'</span>);
</code></pre>
<p>  <strong>Index</strong>: Full-text index on <code>name</code> and <code>description</code></p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'products'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;fullText([<span class="hljs-string">'name'</span>, <span class="hljs-string">'description'</span>]);
  });
</code></pre>
</li>
</ul>
<h3 id="heading-3-optimizing-join-operations">3. <strong>Optimizing Join Operations</strong></h3>
<h4 id="heading-orders-and-products-tables">Orders and Products Tables</h4>
<ul>
<li><p><strong>Query</strong>: Retrieve order details with product information.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> orders.*, products.* <span class="hljs-keyword">FROM</span> orders
  <span class="hljs-keyword">JOIN</span> order_product <span class="hljs-keyword">ON</span> orders.id = order_product.order_id
  <span class="hljs-keyword">JOIN</span> products <span class="hljs-keyword">ON</span> order_product.product_id = products.id
  <span class="hljs-keyword">WHERE</span> orders.user_id = <span class="hljs-number">1</span>;
</code></pre>
<p>  <strong>Index</strong>: Foreign key indexes on <code>order_product</code> table</p>
<pre><code class="lang-php">  Schema::table(<span class="hljs-string">'order_product'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
      $table-&gt;index(<span class="hljs-string">'order_id'</span>);
      $table-&gt;index(<span class="hljs-string">'product_id'</span>);
  });
</code></pre>
</li>
</ul>
<h3 id="heading-4-caching-frequent-queries">4. <strong>Caching Frequent Queries</strong></h3>
<ul>
<li><p><strong>Query</strong>: Retrieve a list of featured products.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products <span class="hljs-keyword">WHERE</span> is_featured = <span class="hljs-number">1</span>;
</code></pre>
<p>  <strong>Cache</strong>: Use Laravel’s caching mechanism to store the result.</p>
<pre><code class="lang-php">  $featuredProducts = Cache::remember(<span class="hljs-string">'featured_products'</span>, <span class="hljs-number">3600</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">return</span> Product::where(<span class="hljs-string">'is_featured'</span>, <span class="hljs-number">1</span>)-&gt;get();
  });
</code></pre>
</li>
</ul>
<h3 id="heading-5-regular-maintenance">5. <strong>Regular Maintenance</strong></h3>
<ul>
<li><p><strong>Check how queries are perform:</strong> By using <code>EXPLAIN</code>, you can gain insights into how MySQL executes your queries and make informed decisions to optimize them.</p>
<p>  Like we have an query like this, now before the query just put a keyword <code>EXPLAIN</code> it will show the result how your query is executed.</p>
</li>
<li><pre><code class="lang-sql">    <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products 
    <span class="hljs-keyword">WHERE</span> category_id = <span class="hljs-number">1</span> 
    <span class="hljs-keyword">AND</span> price <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">100</span> <span class="hljs-keyword">AND</span> <span class="hljs-number">500</span> 
    <span class="hljs-keyword">AND</span> <span class="hljs-keyword">MATCH</span>(<span class="hljs-keyword">name</span>, description) AGAINST(<span class="hljs-string">'laptop'</span>);
</code></pre>
</li>
<li><pre><code class="lang-sql">    <span class="hljs-keyword">EXPLAIN</span> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products 
    <span class="hljs-keyword">WHERE</span> category_id = <span class="hljs-number">1</span> 
    <span class="hljs-keyword">AND</span> price <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">100</span> <span class="hljs-keyword">AND</span> <span class="hljs-number">500</span> 
    <span class="hljs-keyword">AND</span> <span class="hljs-keyword">MATCH</span>(<span class="hljs-keyword">name</span>, description) AGAINST(<span class="hljs-string">'laptop'</span>);
</code></pre>
</li>
<li><p><strong>Monitor Index Usage</strong>: Regularly check which indexes are being used and drop unused ones.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SHOW</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-keyword">FROM</span> products;
</code></pre>
</li>
<li><p><strong>Rebuild Indexes</strong>: Periodically rebuild indexes to reduce fragmentation.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">OPTIMIZE</span> <span class="hljs-keyword">TABLE</span> products;
</code></pre>
</li>
</ul>
<h3 id="heading-example-scenario-improving-product-retrieval">Example Scenario: Improving Product Retrieval</h3>
<p>Consider a scenario where customers frequently search for products based on various filters such as category, price range, and name. Here's how to optimize it:</p>
<h4 id="heading-products-table-structure">Products Table Structure</h4>
<pre><code class="lang-php">Schema::create(<span class="hljs-string">'products'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
    $table-&gt;id();
    $table-&gt;string(<span class="hljs-string">'name'</span>);
    $table-&gt;text(<span class="hljs-string">'description'</span>);
    $table-&gt;unsignedBigInteger(<span class="hljs-string">'category_id'</span>);
    $table-&gt;decimal(<span class="hljs-string">'price'</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>);
    $table-&gt;boolean(<span class="hljs-string">'is_featured'</span>)-&gt;default(<span class="hljs-literal">false</span>);
    $table-&gt;timestamps();

    $table-&gt;index(<span class="hljs-string">'category_id'</span>);
    $table-&gt;index(<span class="hljs-string">'price'</span>);
    $table-&gt;fullText([<span class="hljs-string">'name'</span>, <span class="hljs-string">'description'</span>]);
});
</code></pre>
<h4 id="heading-sample-query-and-indexes">Sample Query and Indexes</h4>
<ul>
<li><p><strong>Query</strong>: Filter products by category and price, and search by name.</p>
<pre><code class="lang-sql">  <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> products 
  <span class="hljs-keyword">WHERE</span> category_id = <span class="hljs-number">1</span> 
  <span class="hljs-keyword">AND</span> price <span class="hljs-keyword">BETWEEN</span> <span class="hljs-number">100</span> <span class="hljs-keyword">AND</span> <span class="hljs-number">500</span> 
  <span class="hljs-keyword">AND</span> <span class="hljs-keyword">MATCH</span>(<span class="hljs-keyword">name</span>, description) AGAINST(<span class="hljs-string">'laptop'</span>);
</code></pre>
<p>  With the above indexes, this query will be optimized for filtering by category and price, and searching by product name and description.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, proper database indexing is essential for optimizing the performance of Laravel applications. By carefully analyzing query patterns and identifying which columns to index, developers can significantly enhance the speed and efficiency of data retrieval operations. This not only improves application responsiveness but also ensures better resource utilization, leading to a more scalable and robust system. Laravel’s migration tools make it straightforward to implement and manage indexes, allowing for easy adjustments as application requirements evolve.</p>
<p>However, it is crucial to strike a balance to avoid over-indexing, which can degrade performance during write operations. Regular monitoring and maintenance of indexes are necessary to ensure they continue to meet the application's needs effectively. By leveraging database-specific tools and Laravel's debugging utilities, developers can fine-tune their indexing strategy to sustain optimal performance. Ultimately, a well-planned indexing approach can dramatically enhance user experience and support the long-term success of a Laravel application.</p>
<p>To know how indexing works, you may see this <a target="_blank" href="https://pankajtanwar.hashnode.dev/how-database-indexing-actually-works-internally">article</a> also.</p>
<blockquote>
<p>End of this Series.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Database Relationships in Laravel]]></title><description><![CDATA[This is a Series of Article to start the series visithere.

Database relationships define how data in one table is related to data in another table. In Laravel, relationships are defined within Eloquent model classes, allowing you to easily query rel...]]></description><link>https://blog.msar.me/database-relationships-in-laravel</link><guid isPermaLink="true">https://blog.msar.me/database-relationships-in-laravel</guid><category><![CDATA[Database Relationship]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Relational Database]]></category><category><![CDATA[Relationship]]></category><category><![CDATA[database design]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 20 May 2024 06:07:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1715847282329/e66e7737-7fe8-4d97-b97e-f66feca66f51.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong><em>This is a Series of Article to start the series visit</em></strong><a target="_blank" href="https://blog.msar.me/series/laravel-db-design"><strong><em>here.</em></strong></a></p>
</blockquote>
<p>Database relationships define how data in one table is related to data in another table. In Laravel, relationships are defined within Eloquent model classes, allowing you to easily query related data and navigate through your application's data structure.</p>
<h3 id="heading-understanding-relationships"><strong>Understanding Relationships</strong></h3>
<p>In Laravel, database relationships empower developers to model complex data structures with ease. Let's delve into a hypothetical scenario: building an e-commerce application. We'll explore how to architect the relationships between <code>User</code>, <code>Product</code>, and <code>Order</code> entities, demonstrating different types of relationships and their practical usage.</p>
<ol>
<li><p><strong>One-to-Many Relationship (User to Order):</strong></p>
<ul>
<li><p>A user can place multiple orders.</p>
</li>
<li><p>Each order belongs to one user.</p>
</li>
</ul>
</li>
<li><p><strong>Many-to-Many Relationship (Order to Product):</strong></p>
<ul>
<li><p>An order can contain multiple products.</p>
</li>
<li><p>A product can be part of multiple orders.</p>
</li>
</ul>
</li>
<li><p><strong>One-to-One Relationship (Order to ShippingAddress):</strong></p>
<ul>
<li>Each order has one associated shipping address.</li>
</ul>
</li>
</ol>
<h3 id="heading-defining-relationships">Defining Relationships</h3>
<p>Laravel supports several types of database relationships, each serving different purposes. Let's explore them with examples:</p>
<h4 id="heading-1-one-to-one-relationship">1. One-to-One Relationship</h4>
<p>In a one-to-one relationship, each record in one table is associated with exactly one record in another table.</p>
<pre><code class="lang-php"><span class="hljs-comment">// User model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">phone</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasOne(Phone::class);
}

<span class="hljs-comment">// Phone model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">user</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsTo(User::class);
}
</code></pre>
<h4 id="heading-2-one-to-many-relationship">2. One-to-Many Relationship</h4>
<p>In a one-to-many relationship, each record in one table can be associated with one or more records in another table.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Post model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">comments</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Comment::class);
}

<span class="hljs-comment">// Comment model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">post</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsTo(Post::class);
}
</code></pre>
<h4 id="heading-3-many-to-many-relationship">3. Many-to-Many Relationship</h4>
<p>In a many-to-many relationship, each record in one table can be associated with one or more records in another table, and vice versa.</p>
<pre><code class="lang-php"><span class="hljs-comment">// User model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">roles</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsToMany(Role::class);
}

<span class="hljs-comment">// Role model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">users</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsToMany(User::class);
}
</code></pre>
<h4 id="heading-4-has-many-through-relationship">4. Has-Many-Through Relationship</h4>
<p>This relationship allows you to define a relationship where a model has a relationship through another model.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Country model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">posts</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasManyThrough(Post::class, User::class);
}
</code></pre>
<h4 id="heading-5-polymorphic-relationship">5. Polymorphic Relationship</h4>
<p>A polymorphic relationship is used when a model can belong to more than one other model on a single association.</p>
<pre><code class="lang-php"><span class="hljs-comment">// Comment model</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">commentable</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;morphTo();
}

<span class="hljs-comment">// Post and Video models</span>
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">comments</span>(<span class="hljs-params"></span>)
</span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;morphMany(Comment::class, <span class="hljs-string">'commentable'</span>);
}
</code></pre>
<h3 id="heading-utilizing-relationships">Utilizing Relationships</h3>
<p>Once relationships are defined, you can easily query related data using Eloquent's expressive syntax. For example:</p>
<pre><code class="lang-php"><span class="hljs-comment">// Retrieve a user's phone number</span>
$user = User::find(<span class="hljs-number">1</span>);
$phone = $user-&gt;phone;

<span class="hljs-comment">// Retrieve a post's comments</span>
$post = Post::find(<span class="hljs-number">1</span>);
$comments = $post-&gt;comments;

<span class="hljs-comment">// Retrieve a user's roles</span>
$user = User::find(<span class="hljs-number">1</span>);
$roles = $user-&gt;roles;

<span class="hljs-comment">// Eager loading to prevent N+1 query issues</span>
$users = User::with(<span class="hljs-string">'roles'</span>)-&gt;get();

<span class="hljs-comment">// Querying through relationships</span>
$country = Country::find(<span class="hljs-number">1</span>);
$posts = $country-&gt;posts;
</code></pre>
<h4 id="heading-eager-loading-amp-the-n1-query-problem">Eager Loading &amp; The N+1 Query Problem</h4>
<p>When you don't use eager loading in Laravel, you may encounter the "N+1 query problem." This problem occurs when your application executes one query to retrieve a list of records and then executes additional queries for each record to retrieve related data. This can lead to performance issues, especially with large datasets.</p>
<pre><code class="lang-php"><span class="hljs-comment">// User.php (Model)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">posts</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hasMany(Post::class);
    }
}

<span class="hljs-comment">// In a controller or somewhere else</span>
$users = User::all();

<span class="hljs-keyword">foreach</span> ($users <span class="hljs-keyword">as</span> $user) {
    <span class="hljs-comment">// This will execute an additional query for each user</span>
    $posts = $user-&gt;posts;
}
</code></pre>
<p>In the above code, if you have 10 users, the application will execute the following queries:</p>
<ol>
<li><p>One query to retrieve all users:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>;
</code></pre>
</li>
<li><p>Ten additional queries to retrieve posts for each user:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> posts <span class="hljs-keyword">WHERE</span> user_id = <span class="hljs-number">1</span>;
 <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> posts <span class="hljs-keyword">WHERE</span> user_id = <span class="hljs-number">2</span>;
 <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> posts <span class="hljs-keyword">WHERE</span> user_id = <span class="hljs-number">3</span>;
 ...
 <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> posts <span class="hljs-keyword">WHERE</span> user_id = <span class="hljs-number">10</span>;
</code></pre>
</li>
</ol>
<p>This results in a total of 11 queries. As the number of users grows, the number of queries increases linearly, leading to significant performance issues.</p>
<h4 id="heading-impact-on-performance">Impact on Performance</h4>
<p>The performance impact can be severe due to the following reasons:</p>
<ol>
<li><p><strong>Increased Database Load:</strong> Executing a large number of queries puts more load on the database server.</p>
</li>
<li><p><strong>Longer Response Times:</strong> More queries mean longer response times, as each query has overhead.</p>
</li>
<li><p><strong>Inefficiency:</strong> Many queries retrieving small amounts of data repeatedly are less efficient than fewer queries retrieving larger amounts of data.</p>
</li>
</ol>
<h4 id="heading-solving-the-problem-with-eager-loading">Solving the Problem with Eager Loading</h4>
<p>Eager loading can solve this problem by retrieving the related data in a single query.</p>
<ol>
<li><strong>Using Eager Loading:</strong></li>
</ol>
<pre><code class="lang-php"><span class="hljs-comment">// In a controller or somewhere else</span>
$users = User::with(<span class="hljs-string">'posts'</span>)-&gt;get();
</code></pre>
<ol start="2">
<li><strong>Generated Queries with Eager Loading:</strong></li>
</ol>
<p>With eager loading, Laravel will execute the following queries:</p>
<ol>
<li><p>One query to retrieve all users:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>;
</code></pre>
</li>
<li><p>One query to retrieve all posts for those users:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> posts <span class="hljs-keyword">WHERE</span> user_id <span class="hljs-keyword">IN</span> (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, ..., <span class="hljs-number">10</span>);
</code></pre>
</li>
</ol>
<p>This results in a total of 2 queries regardless of the number of users, significantly improving performance.</p>
<p>Without eager loading, you risk running into the N+1 query problem, which can degrade your application's performance. Eager loading allows you to optimize the number of queries executed, leading to faster response times and a more efficient application. Here's a comparison for clarity:</p>
<ul>
<li><p><strong>Without Eager Loading:</strong></p>
<ul>
<li><p>N + 1 queries (1 query for users + N queries for posts)</p>
</li>
<li><p>Slower response times</p>
</li>
<li><p>Higher database load</p>
</li>
</ul>
</li>
<li><p><strong>With Eager Loading:</strong></p>
<ul>
<li><p>2 queries (1 query for users + 1 query for posts)</p>
</li>
<li><p>Faster response times</p>
</li>
<li><p>Lower database load</p>
</li>
</ul>
</li>
</ul>
<p>By using eager loading, you ensure that your application remains performant and scalable.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Laravel's Eloquent ORM provides a powerful and intuitive way to define and work with database relationships. By understanding and utilizing these relationships effectively, you can build complex applications with ease, while maintaining a clean and expressive codebase. Whether you're working with simple one-to-one relationships or complex many-to-many relationships, Laravel's Eloquent has you covered.</p>
]]></content:encoded></item><item><title><![CDATA[Database Join Queries]]></title><description><![CDATA[This is a Series of Article to start the series visit here.

In the realm of web development, database interactions are crucial for storing, retrieving, and manipulating data efficiently. Laravel, a popular PHP framework, offers robust support for da...]]></description><link>https://blog.msar.me/database-join-queries</link><guid isPermaLink="true">https://blog.msar.me/database-join-queries</guid><category><![CDATA[Databases]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[joins]]></category><category><![CDATA[Database Join Algorithms]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Thu, 16 May 2024 14:12:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/k39RGHmLoV8/upload/502b973a4cbdf4f21edf993a7ab617bf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong><em>This is a Series of Article to start the series visit</em></strong> <a target="_blank" href="https://blog.msar.me/series/laravel-db-design"><strong><em>here.</em></strong></a></p>
</blockquote>
<p>In the realm of web development, database interactions are crucial for storing, retrieving, and manipulating data efficiently. Laravel, a popular PHP framework, offers robust support for database operations, making it a favorite among developers. One fundamental aspect of working with databases is mastering the art of join queries. In this article, we'll delve into various aspects of database join queries using MySQL, illustrating each concept with practical examples implemented in Laravel.</p>
<h3 id="heading-understanding-mysql-join-types"><strong>Understanding MySQL Join Types</strong></h3>
<p>MySQL joins are a fundamental concept for retrieving data from multiple tables in your database. Here's a breakdown of the different join types you'll encounter:</p>
<p><strong>1. INNER JOIN (or Simple JOIN):</strong></p>
<ul>
<li><p>This is the most common type of join.</p>
</li>
<li><p>It returns only records that have matching values in both tables based on the join condition.</p>
</li>
<li><p>Imagine it like finding the intersection between two sets of data.</p>
</li>
</ul>
<p><strong>2. OUTER JOINs:</strong></p>
<ul>
<li><p>Outer joins return records from one table (the outer table) along with matching records from the other table (the inner table).</p>
</li>
<li><p>There are two main types of outer joins:</p>
<ul>
<li><p><strong>LEFT JOIN (or LEFT OUTER JOIN):</strong></p>
<ul>
<li><p>This returns all records from the left table, and matching records from the right table.</p>
</li>
<li><p>For rows in the left table without a match in the right table, null values are filled in the right table's columns.</p>
</li>
</ul>
</li>
<li><p><strong>RIGHT JOIN (or RIGHT OUTER JOIN):</strong></p>
<ul>
<li><p>This is the opposite of LEFT JOIN.</p>
</li>
<li><p>It returns all records from the right table, and matching records from the left table.</p>
</li>
<li><p>Null values are filled in the left table's columns for unmatched rows in the right table.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>3. FULL JOIN:</strong></p>
<ul>
<li><p>A FULL JOIN returns all records from both tables, regardless of whether there's a match in the other table.</p>
</li>
<li><p>It combines the results of a LEFT JOIN and a RIGHT JOIN.</p>
</li>
<li><p>Rows without matches in either table will have null values in the corresponding columns.</p>
</li>
</ul>
<p><strong>4. CROSS JOIN (Cartesian Product):</strong></p>
<ul>
<li><p>This is the least commonly used join type.</p>
</li>
<li><p>It creates a new result set by pairing every row from one table with every row from the other table.</p>
</li>
<li><p>This can result in a very large dataset, so use it cautiously.pen_spark</p>
</li>
</ul>
<p>Let's illustrate these concepts with a scenario. Consider two tables: <code>users</code> and <code>orders</code>. We want to retrieve a list of users along with their corresponding orders, if any.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> orders <span class="hljs-keyword">ON</span> users.id = orders.user_id;
</code></pre>
<p>To implement this sql query in Laravel we can use like this below.</p>
<pre><code class="lang-php">$users = User::join(<span class="hljs-string">'orders'</span>, <span class="hljs-string">'users.id'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'orders.user_id'</span>)
  -&gt;select(<span class="hljs-string">'*'</span>)
  -&gt;get();
</code></pre>
<h3 id="heading-grouping-results-with-aggregate-functions"><strong>Grouping Results With Aggregate Functions</strong></h3>
<p>Aggregate functions process multiple rows of data and return a single summarized value. Common examples include:</p>
<ul>
<li><p><code>COUNT(*)</code>: Counts the total number of rows in a group (often used with <code>*</code> to indicate all rows).</p>
</li>
<li><p><code>SUM(column_name)</code>: Calculates the total sum of a specific column's values within a group.</p>
</li>
<li><p><code>AVG(column_name)</code>: Computes the average value of a specific column for each group.</p>
</li>
<li><p><code>MIN(column_name)</code>: Returns the minimum value of a specific column within a group.</p>
</li>
<li><p><code>MAX(column_name)</code>: Returns the maximum value of a specific column within a group.</p>
</li>
</ul>
<p><strong>Grouping Data:</strong></p>
<p>The <code>GROUP BY</code> clause specifies the column(s) to use for grouping the results. Rows with the same value(s) in the specified column(s) are grouped together, and aggregate functions are then applied to each group.</p>
<p><strong>Example: Counting Orders per User</strong></p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> users.name, <span class="hljs-keyword">COUNT</span>(orders.id) <span class="hljs-keyword">AS</span> order_count
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> orders <span class="hljs-keyword">ON</span> users.id = orders.user_id
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> users.id;
</code></pre>
<p><strong>Explanation:</strong></p>
<ol>
<li><p><strong>SELECT</strong>: We select two columns: <code>users.name</code> and the result of <code>COUNT(orders.id)</code> aliased as <code>order_count</code>.</p>
</li>
<li><p><strong>FROM</strong>: We specify the <code>users</code> table as the source.</p>
</li>
<li><p><strong>LEFT JOIN</strong>: We perform a LEFT JOIN with the <code>orders</code> table on the condition <code>users.id = orders.user_id</code>.</p>
</li>
<li><p><strong>GROUP BY</strong>: We group the results by the <code>users.id</code> column.</p>
</li>
</ol>
<p>This query retrieves the name of each user and the total number of orders they have placed. Users without any orders will still be included with a <code>NULL</code> value for <code>order_count</code>.</p>
<p><strong>Laravel Example:</strong></p>
<pre><code class="lang-php">$results = User::select(<span class="hljs-string">'users.name'</span>, DB::raw(<span class="hljs-string">'COUNT(orders.id) AS order_count'</span>))
  -&gt;leftJoin(<span class="hljs-string">'orders'</span>, <span class="hljs-string">'users.id'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'orders.user_id'</span>)
  -&gt;groupBy(<span class="hljs-string">'users.id'</span>)
  -&gt;get();
</code></pre>
<p><strong>Explanation:</strong></p>
<ol>
<li><p><strong>User::</strong>: We start with the <code>User</code> model.</p>
</li>
<li><p><strong>select</strong>: We define the columns to be retrieved: <code>users.name</code> and the result of <code>DB::raw('COUNT(orders.id) AS order_count')</code>.</p>
</li>
<li><p><strong>leftJoin</strong>: Similar to the SQL query, we perform a LEFT JOIN.</p>
</li>
<li><p><strong>groupBy</strong>: We group the results by <code>users.id</code>.</p>
</li>
<li><p><strong>get</strong>: We execute the query and retrieve the results as a collection of <code>User</code> models.</p>
</li>
</ol>
<p>This code achieves the same functionality as the SQL query, but with a more Laravel-specific syntax using Eloquent.</p>
<h3 id="heading-performing-multiple-joins-in-one-query"><strong>Performing Multiple Joins in One Query</strong></h3>
<p>In real-world scenarios, it's common to join more than two tables in a single query to retrieve comprehensive data. Laravel provides an elegant syntax for achieving this with its ORM (Object-Relational Mapping) capabilities.</p>
<p>Suppose we have three tables: <code>users</code>, <code>orders</code>, and <code>products</code>. We want to retrieve user details along with the products they have ordered.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> users.name, orders.id <span class="hljs-keyword">AS</span> order_id, products.name <span class="hljs-keyword">AS</span> product_name
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> orders <span class="hljs-keyword">ON</span> users.id = orders.user_id
<span class="hljs-keyword">INNER</span> <span class="hljs-keyword">JOIN</span> products <span class="hljs-keyword">ON</span> orders.product_id = products.id;
</code></pre>
<pre><code class="lang-php">$results = User::select(<span class="hljs-string">'users.name'</span>, <span class="hljs-string">'orders.id AS order_id'</span>, <span class="hljs-string">'products.name AS product_name'</span>)
  -&gt;join(<span class="hljs-string">'orders'</span>, <span class="hljs-string">'users.id'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'orders.user_id'</span>)
  -&gt;join(<span class="hljs-string">'products'</span>, <span class="hljs-string">'orders.product_id'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'products.id'</span>)
  -&gt;get();
</code></pre>
<h3 id="heading-filtering-aggregated-data"><strong>Filtering Aggregated Data</strong></h3>
<p>Filtering aggregated data involves applying conditions to aggregated results. This is commonly done using the <code>HAVING</code> clause in SQL queries.</p>
<p>For instance, let's filter users based on the total number of orders they've placed:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> users.name, <span class="hljs-keyword">COUNT</span>(orders.id) <span class="hljs-keyword">AS</span> order_count
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span>
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> orders <span class="hljs-keyword">ON</span> users.id = orders.user_id
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> users.id
<span class="hljs-keyword">HAVING</span> order_count &gt; <span class="hljs-number">5</span>;
</code></pre>
<p>In Laravel, achieving the same result is straightforward:</p>
<pre><code class="lang-php">$users = User::select(<span class="hljs-string">'users.name'</span>, DB::raw(<span class="hljs-string">'COUNT(orders.id) AS order_count'</span>))
    -&gt;leftJoin(<span class="hljs-string">'orders'</span>, <span class="hljs-string">'users.id'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'orders.user_id'</span>)
    -&gt;groupBy(<span class="hljs-string">'users.id'</span>)
    -&gt;having(<span class="hljs-string">'order_count'</span>, <span class="hljs-string">'&gt;'</span>, <span class="hljs-number">5</span>)
    -&gt;get();
</code></pre>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>By understanding the various join types, leveraging aggregate functions, performing multiple joins, and filtering aggregated data, developers can efficiently retrieve and manipulate data from multiple tables. With MySQL and Laravel's powerful tools and syntax, developers have everything they need to handle complex data operations seamlessly, ensuring the smooth functioning of their applications.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Database Keys]]></title><description><![CDATA[This is a Series of Article to start the series visit here.


In Laravel, database keys play a crucial role in defining relationships between different tables and ensuring data integrity. Keys help maintain the integrity and efficiency of the databas...]]></description><link>https://blog.msar.me/understanding-database-keys</link><guid isPermaLink="true">https://blog.msar.me/understanding-database-keys</guid><category><![CDATA[Database keys]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><category><![CDATA[database]]></category><category><![CDATA[primary key]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Wed, 15 May 2024 19:42:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ZfVyuV8l7WU/upload/fb6712143ad3917136aa85d72137122c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This is a Series of Article to start the series visit <a target="_blank" href="https://blog.msar.me/series/laravel-db-design">here</a>.</p>
</blockquote>
<hr />
<p>In Laravel, database keys play a crucial role in defining relationships between different tables and ensuring data integrity. Keys help maintain the integrity and efficiency of the database by enforcing uniqueness and establishing relationships between tables. In this article, we'll explore the different types of keys used in Laravel migrations and how they are implemented. In this article we will use <a target="_blank" href="https://laravel.com/docs/11.x/installation">Laravel 11</a>.</p>
<h2 id="heading-primary-key">Primary Key</h2>
<p>A primary key uniquely identifies each record in a table. In Laravel migrations, you can define a primary key using the <code>increments</code> or <code>bigIncrements</code> method. Here's an example:</p>
<pre><code class="lang-php">Schema::create(<span class="hljs-string">'users'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
    $table-&gt;id();
    $table-&gt;string(<span class="hljs-string">'name'</span>);
    $table-&gt;string(<span class="hljs-string">'email'</span>)-&gt;unique();
    $table-&gt;timestamps();
});
</code></pre>
<p>In this example, the <code>id</code> column is defined as the primary key using the <code>bigIncrements</code> method, which generates a big integer auto-incrementing ID.</p>
<h2 id="heading-foreign-key">Foreign Key</h2>
<p>Foreign keys establish relationships between tables by referencing the primary key of another table. In Laravel migrations, you can define a foreign key using the <code>foreign</code> method. Here's an example of creating a foreign key in a migration:</p>
<pre><code class="lang-php">Schema::table(<span class="hljs-string">'posts'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
    $table-&gt;id();
    $table-&gt;foreignId(<span class="hljs-string">'user_id'</span>)-&gt;constrained()-&gt;onDelete(<span class="hljs-string">'cascade'</span>);
    $table-&gt;string(<span class="hljs-string">'title'</span>);
    $table-&gt;string(<span class="hljs-string">'slug'</span>)-&gt;unique();
    $table-&gt;text(<span class="hljs-string">'content'</span>)-&gt;nullable();
    $table-&gt;timestamps();
});
</code></pre>
<p>In this example, we're adding a <code>user_id</code> column to the <code>posts</code> table, which references the <code>id</code> column of the <code>users</code> table. The <code>foreign</code> method establishes this relationship.</p>
<h2 id="heading-unique-key">Unique Key</h2>
<p>A unique key ensures that the values in a column are unique across all records in the table. In Laravel migrations, you can define a unique key using the <code>unique</code> method. Here's an example:</p>
<pre><code class="lang-php">Schema::create(<span class="hljs-string">'roles'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
    $table-&gt;id();
    $table-&gt;string(<span class="hljs-string">'name'</span>)-&gt;unique();
    $table-&gt;timestamps();
});
</code></pre>
<p>In this example, the <code>name</code> column is defined as unique using the <code>unique</code> method. This ensures that each role name is unique within the <code>roles</code> table.</p>
<h2 id="heading-composite-key">Composite Key</h2>
<p>A composite key consists of multiple columns that, together, uniquely identify each record in a table. In Laravel migrations, you can define a composite key using the <code>primary</code> method with an array of column names. Here's an example:</p>
<pre><code class="lang-php">Schema::create(<span class="hljs-string">'orders'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">Blueprint $table</span>) </span>{
    $table-&gt;foreignId(<span class="hljs-string">'user_id'</span>)-&gt;constrained()-&gt;onDelete(<span class="hljs-string">'cascade'</span>);
    $table-&gt;foreignId(<span class="hljs-string">'product_id'</span>)-&gt;constrained()-&gt;onDelete(<span class="hljs-string">'cascade'</span>);

    $table-&gt;primary([<span class="hljs-string">'customer_id'</span>, <span class="hljs-string">'product_id'</span>]);
});
</code></pre>
<p>In this example, the composite key consists of the <code>customer_id</code> and <code>product_id</code> columns, which together uniquely identify each order. We use the <code>primary</code> method to define this composite key.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Understanding and properly utilizing database keys is essential for designing efficient and maintainable database schemas in Laravel applications. Whether it's defining primary keys for uniqueness, foreign keys for relationships, unique keys for data integrity, or composite keys for complex relationships, Laravel provides powerful tools for managing database keys effectively.</p>
<p>By leveraging these features, Laravel developers can ensure the integrity and efficiency of their database structures, leading to robust and scalable applications.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Design Patterns: Best Practices for Building Scalable and Maintainable Code]]></title><description><![CDATA[Introduction
JavaScript design patterns are essential tools for developers seeking to write clean, efficient, and maintainable code. By following established patterns, developers can structure their code in a way that promotes scalability, reusabilit...]]></description><link>https://blog.msar.me/javascript-design-patterns-best-practices-for-building-scalable-and-maintainable-code</link><guid isPermaLink="true">https://blog.msar.me/javascript-design-patterns-best-practices-for-building-scalable-and-maintainable-code</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Thu, 29 Feb 2024 05:47:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/7Y0NshQLohk/upload/21f2d40b8c4c64b091e1ff05fc789ffd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>JavaScript design patterns are essential tools for developers seeking to write clean, efficient, and maintainable code. By following established patterns, developers can structure their code in a way that promotes scalability, reusability, and ease of maintenance. In this article, we'll delve into some of the most widely used design patterns in JavaScript, highlighting their benefits and providing practical examples for implementation.</p>
<p>The Importance of Design Patterns: In the realm of software development, design patterns serve as proven solutions to recurring problems. They encapsulate best practices and design principles that enable developers to write code that is modular, flexible, and resilient to change. By leveraging design patterns, developers can streamline development workflows, reduce bugs, and improve code readability.</p>
<ol>
<li><strong>Module Pattern:</strong> The Module Pattern is a widely used design pattern in JavaScript for creating encapsulated modules with private and public methods. By using closures, developers can achieve data encapsulation and prevent the pollution of the global namespace, resulting in cleaner and more maintainable code.</li>
</ol>
<p>Example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> <span class="hljs-built_in">module</span> = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> privateVariable = <span class="hljs-string">'I am private'</span>;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">privateMethod</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Private Method'</span>);
  }

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">publicMethod</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Public Method'</span>);
    }
  };
})();
</code></pre>
<ol>
<li><strong>Singleton Pattern</strong>: The Singleton Pattern ensures that a class has only one instance and provides a global point of access to that instance. This pattern is useful for managing global state and resources in applications, ensuring that there are no duplicate instances and facilitating centralized management.</li>
</ol>
<p>Example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> Singleton = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> instance;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createInstance</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Singleton logic</span>
    <span class="hljs-keyword">return</span> {};
  }

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">getInstance</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">if</span> (!instance) {
        instance = createInstance();
      }
      <span class="hljs-keyword">return</span> instance;
    }
  };
})();
</code></pre>
<ol>
<li><strong>Observer Pattern</strong>: The Observer Pattern facilitates communication between objects by defining a one-to-many dependency relationship. When the state of an object changes, all its dependents are notified and updated automatically. This pattern is commonly used in event-driven architectures and UI frameworks.</li>
</ol>
<p>Example:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Subject</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.observers = [];

  <span class="hljs-built_in">this</span>.addObserver = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">observer</span>) </span>{
    <span class="hljs-built_in">this</span>.observers.push(observer);
  };

  <span class="hljs-built_in">this</span>.notifyObservers = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">this</span>.observers.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">observer</span>) </span>{
      observer.update();
    });
  };
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Observer</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">this</span>.update = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Updated'</span>);
  };
}

<span class="hljs-keyword">var</span> subject = <span class="hljs-keyword">new</span> Subject();
<span class="hljs-keyword">var</span> observer = <span class="hljs-keyword">new</span> Observer();

subject.addObserver(observer);
subject.notifyObservers();
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>JavaScript design patterns offer a systematic approach to structuring code, promoting scalability and maintainability in software development projects. By incorporating patterns like the Module Pattern, Singleton Pattern, and Observer Pattern into their workflows, developers can write cleaner, more efficient code that is easier to understand, debug, and extend. As you continue to explore and apply design patterns in your JavaScript projects, remember to prioritize readability, flexibility, and adherence to best practices to achieve optimal results.</p>
]]></content:encoded></item><item><title><![CDATA[Hello ADB - Cheat Sheet]]></title><description><![CDATA[Android Debug Bridge (adb) is a versatile command-line tool that lets you communicate with a device. The adb command facilitates a variety of device actions, such as installing and debugging apps, and it provides access to a Unix shell that you can u...]]></description><link>https://blog.msar.me/hello-adb-cheat-sheet</link><guid isPermaLink="true">https://blog.msar.me/hello-adb-cheat-sheet</guid><category><![CDATA[Android Debug]]></category><category><![CDATA[adb]]></category><category><![CDATA[Android]]></category><category><![CDATA[debugging]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Sun, 04 Feb 2024 18:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/npxXWgQ33ZQ/upload/32b6d0ac472560d880ebf1a82c3d0d2d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Android Debug Bridge (adb)</strong> is a versatile <strong>command-line</strong> tool that lets you communicate with a device. The adb command facilitates a variety of device actions, such as installing and debugging apps, and it provides access to a Unix shell that you can use to run a variety of commands on a device. It is a client-server program that includes three components:</p>
<ul>
<li><p>A client, which sends commands. The client runs on your development machine. You can invoke a client from a command-line terminal by issuing an adb command.</p>
</li>
<li><p>A daemon (adbd), which runs commands on a device. The daemon runs as a background process on each device.</p>
</li>
<li><p>A server, which manages communication between the client and the daemon. The server runs as a background process on your development machine.</p>
</li>
</ul>
<p>Here is a list of adb commands and there usages.</p>
<h2 id="heading-adb-basics">ADB Basics</h2>
<p><strong>adb devices</strong> (lists connected devices)<br /><strong>adb root</strong> (restarts adbd with root permissions)<br /><strong>adb start-server</strong> (starts the adb server)<br /><strong>adb kill-server</strong> (kills the adb server)<br /><strong>adb reboot</strong> (reboots the device)<br /><strong>adb devices -l</strong> (list of devices by product/model)<br /><strong>adb shell</strong> (starts the backround terminal)<br /><strong>exit</strong> (exits the background terminal)<br /><strong>adb help</strong> (list all commands)<br /><strong>adb -s</strong> (redirect command to specific device)<br /><strong>adb –d</strong> (directs command to only attached USB device)<br /><strong>adb –e</strong> (directs command to only attached emulator)</p>
<h2 id="heading-package-installation">Package Installation</h2>
<p><strong>adb shell install</strong> (install app)<br /><strong>adb shell install</strong> (install app from phone path)<br /><strong>adb shell install -r</strong> (install app from phone path)<br /><strong>adb shell uninstall</strong> (remove the app)</p>
<h2 id="heading-paths">Paths</h2>
<p><strong>/data/data//databases</strong> (app databases)<br /><strong>/data/data//shared_prefs/</strong> (shared preferences)<br /><strong>/data/app</strong> (apk installed by user)<br /><strong>/system/app</strong> (pre-installed APK files)<br /><strong>/mmt/asec</strong> (encrypted apps) (App2SD)<br /><strong>/mmt/emmc</strong> (internal SD Card)<br /><strong>/mmt/adcard</strong> (external/Internal SD Card)<br /><strong>/mmt/adcard/external_sd</strong> (external SD Card)</p>
<p><strong>adb shell ls</strong> (list directory contents)<br /><strong>adb shell ls -s</strong> (print size of each file)<br /><strong>adb shell ls -R</strong> (list subdirectories recursively)</p>
<h2 id="heading-file-operations">File Operations</h2>
<p><strong>adb push</strong> (copy file/dir to device)<br /><strong>adb pull</strong> (copy file/dir from device)<br /><strong>run-as cat</strong> (access the private package files)</p>
<h2 id="heading-phone-info">Phone Info</h2>
<p><strong>adb get-statе</strong> (print device state)<br /><strong>adb get-serialno</strong> (get the serial number)<br /><strong>adb shell dumpsys iphonesybinfo</strong> (get the IMEI)<br /><strong>adb shell netstat</strong> (list TCP connectivity)<br /><strong>adb shell pwd</strong> (print current working directory)<br /><strong>adb shell dumpsys battery</strong> (battery status)<br /><strong>adb shell pm list features</strong> (list phone features)<br /><strong>adb shell service list</strong> (list all services)<br /><strong>adb shell dumpsys activity /</strong> (activity info)<br /><strong>adb shell ps</strong> (print process status)<br /><strong>adb shell wm size</strong> (displays the current screen resolution)<br /><strong>dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'</strong> (print current app's opened activity)</p>
<h2 id="heading-package-info">Package Info</h2>
<p><strong>adb shell list packages</strong> (list package names)<br /><strong>adb shell list packages -r</strong> (list package name + path to apks)<br /><strong>adb shell list packages -3</strong> (list third party package names)<br /><strong>adb shell list packages -s</strong> (list only system packages)<br /><strong>adb shell list packages -u</strong> (list package names + uninstalled)<br /><strong>adb shell dumpsys package packages</strong> (list info on all apps)<br /><strong>adb shell dump</strong> (list info on one package)<br /><strong>adb shell path</strong> (path to the apk file)</p>
<h2 id="heading-configure-settings-commands">Configure Settings Commands</h2>
<p><strong>adb shell dumpsys battery set level</strong> (change the level from 0 to 100)<br /><strong>adb shell dumpsys battery set status</strong> (change the level to unknown, charging, discharging, not charging or full)<br /><strong>adb shell dumpsys battery reset</strong> (reset the battery)<br /><strong>adb shell dumpsys battery set usb</strong> (change the status of USB connection. ON or OFF)<br /><strong>adb shell wm size WxH</strong> (sets the resolution to WxH)</p>
<h2 id="heading-device-related-commands">Device Related Commands</h2>
<p><strong>adb reboot-recovery</strong> (reboot device into recovery mode)<br /><strong>adb reboot fastboot</strong> (reboot device into recovery mode)<br /><strong>adb shell screencap -p "/path/to/screenshot.png"</strong> (capture screenshot)<br /><strong>adb shell screenrecord "/path/to/</strong><a target="_blank" href="http://record.mp"><strong>record.mp</strong></a><strong>4"</strong> (record device screen)<br /><strong>adb backup -apk -all -f backup.ab</strong> (backup settings and apps)<br /><strong>adb backup -apk -shared -all -f backup.ab</strong> (backup settings, apps and shared storage)<br /><strong>adb backup -apk -nosystem -all -f backup.ab</strong> (backup only non-system apps)<br /><strong>adb restore backup.ab</strong> (restore a previous backup)<br /><strong>adb shell am start|startservice|broadcast []<br />-a e.g. android.intent.action.VIEW<br />-c e.g. android.intent.category.LAUNCHER</strong> (start activity intent)</p>
<p><strong>adb shell am start -a android.intent.action.VIEW -d URL</strong> (open URL)<br /><strong>adb shell am start -t image/* -a android.intent.action.VIEW</strong> (opens gallery)</p>
<h2 id="heading-logs">Logs</h2>
<p><strong>adb logcat [options] [filter] [filter]</strong> (view device log)<br /><strong>adb bugreport</strong> (print bug reports)</p>
<h2 id="heading-permissions">Permissions</h2>
<p><strong>adb shell permissions groups</strong> (list permission groups definitions)<br /><strong>adb shell list permissions -g -r</strong> (list permissions details)</p>
<p>This post collected from <a target="_blank" href="https://www.automatetheplanet.com/adb-cheat-sheet/">Here</a></p>
]]></content:encoded></item><item><title><![CDATA[Deep Diving into React Hooks]]></title><description><![CDATA[React Hooks revolutionized the way developers approach state management and lifecycle methods in React functional components. Introduced in React 16.8, Hooks provide a more elegant and efficient way to handle stateful logic, side effects, and more wi...]]></description><link>https://blog.msar.me/deep-diving-into-react-hooks</link><guid isPermaLink="true">https://blog.msar.me/deep-diving-into-react-hooks</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Sat, 06 Jan 2024 18:30:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TxzjVxnWYq4/upload/73eb8074f3b5bd9809e81d6602e10bd6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>React Hooks revolutionized the way developers approach state management and lifecycle methods in React functional components. Introduced in React 16.8, Hooks provide a more elegant and efficient way to handle stateful logic, side effects, and more within functional components. Among the plethora of available Hooks, let’s embark on a deep dive into some key React Hooks, exploring their functionalities with practical examples.</p>
<h2 id="heading-understanding-react-hooks">Understanding React Hooks</h2>
<p>Here are the most commonly used built-in React hooks:</p>
<ul>
<li><p><strong>useState:</strong> Manages state variables within functional components.</p>
</li>
<li><p><strong>useReducer:</strong> An alternative to useState for complex state logic, often used with many state variables that update interdependently.</p>
</li>
<li><p><strong>useEffect:</strong> Performs side effects, such as data fetching, subscriptions, or manually changing the DOM.</p>
</li>
<li><p><strong>useLayoutEffect:</strong> Similar to useEffect, but fires synchronously after DOM mutations.</p>
</li>
<li><p><strong>useContext:</strong> Accesses context values for sharing data across components without prop drilling.</p>
</li>
<li><p><strong>useRef:</strong> Creates mutable ref objects to hold references to DOM elements or other values.</p>
</li>
<li><p><strong>useCallback:</strong> Memoizes callback functions to prevent unnecessary re-renders.</p>
</li>
<li><p><strong>useMemo:</strong> Memoizes expensive computations to avoid re-calculations on every render.</p>
</li>
<li><p><strong>useImperativeHandle:</strong> Customizes the instance value exposed to parent components when using ref.</p>
</li>
<li><p><strong>useId:</strong> Generates unique IDs that are stable across server and client rendering.</p>
</li>
<li><p><strong>useInsertionEffect:</strong> Schedules effects to run before DOM mutations.</p>
</li>
<li><p><strong>useTransition:</strong> Pauses or suspends non-urgent updates for a smoother user experience.</p>
</li>
<li><p><strong>useDeferredValue:</strong> Defer re-renders of heavy components until the next screen frame.</p>
</li>
</ul>
<p>Remember that React's hook system is designed to be extensible, so you can create your own custom hooks to encapsulate reusable stateful logic and share it across your components. Here is some example of useful react hooks.</p>
<h3 id="heading-usestate">useState</h3>
<p><code>useState</code> is a fundamental Hook used for managing state within functional components. It allows components to declare and utilize state variables. Consider an example of a simple counter:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setCount(count + 1)}&gt;Increment<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>
  );
}
</code></pre>
<p>In this snippet, <code>useState</code> initializes the <code>count</code> state variable with an initial value of <code>0</code>. The <code>setCount</code> function updates the <code>count</code> state, triggering re-renders when its value changes.</p>
<h3 id="heading-useeffect">useEffect</h3>
<p><code>useEffect</code> is another crucial Hook used for handling side effects in functional components, such as data fetching, subscriptions, or manual DOM manipulations. Here’s an example demonstrating its usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DataFetcher</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Simulating data fetching from an API</span>
    fetch(<span class="hljs-string">'https://api.example.com/data'</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> setData(result))
      .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
  }, []); <span class="hljs-comment">// Empty dependency array runs the effect only once</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {data ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Data: {data}<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>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here, <code>useEffect</code> runs after the component renders and performs the data fetching operation using <code>fetch</code>. The empty dependency array ensures the effect runs only once, simulating a <code>componentDidMount</code> behavior.</p>
<h3 id="heading-usecontext">useContext</h3>
<p>The <code>useContext</code> Hook allows components to consume values from React Context. It’s handy for accessing global data without prop drilling. Consider this usage example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ThemeContext = React.createContext(<span class="hljs-string">'light'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThemeComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Current Theme: {theme}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}
</code></pre>
<p>In this snippet, <code>useContext(ThemeContext)</code> retrieves the current value provided by the <code>ThemeContext</code>.</p>
<h3 id="heading-custom-hooks">Custom Hooks</h3>
<p>Custom Hooks enable developers to extract component logic into reusable functions, allowing shared stateful logic across components. Let’s create a custom Hook for handling a form input:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useFormInput</span>(<span class="hljs-params">initialValue</span>) </span>{
  <span class="hljs-keyword">const</span> [value, setValue] = useState(initialValue);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleChange</span>(<span class="hljs-params">e</span>) </span>{
    setValue(e.target.value);
  }

  <span class="hljs-keyword">return</span> {
    value,
    <span class="hljs-attr">onChange</span>: handleChange,
  };
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FormComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> name = useFormInput(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> email = useFormInput(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> {<span class="hljs-attr">...name</span>} <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Name"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> {<span class="hljs-attr">...email</span>} <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>In this example, <code>useFormInput</code> is a custom Hook managing the state of form inputs, returning value and onChange functions, simplifying form management across components.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>React Hooks have significantly enhanced the development experience by offering a more concise and functional approach to managing state and side effects in React components. Understanding and leveraging these Hooks empower developers to create cleaner, more maintainable, and efficient code. As you explore further, you'll discover various other Hooks catering to different scenarios, enabling you to craft more robust and dynamic React applications.</p>
<p><strong>Resources:</strong></p>
<ul>
<li><a target="_blank" href="https://react.dev/reference/react/hooks">https://react.dev/reference/react/hooks</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Github Actions - Your secret weapon]]></title><description><![CDATA[Imagine code evolving like a living organism, each tweak and fix captured like snapshots in a digital album. That's the magic of Git, a version control system that tracks your code's history. Think of it as a time machine for your project, letting yo...]]></description><link>https://blog.msar.me/github-actions-your-secret-weapon</link><guid isPermaLink="true">https://blog.msar.me/github-actions-your-secret-weapon</guid><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[GitHub Actions]]></category><category><![CDATA[Devops]]></category><category><![CDATA[CI/CD]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 01 Jan 2024 11:25:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wX2L8L-fGeA/upload/c5e672d1fce2cae677bb34fdfeabb614.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine code evolving like a living organism, each tweak and fix captured like snapshots in a digital album. That's the magic of <strong>Git</strong>, a <strong><em>version control system</em></strong> that tracks your code's history. Think of it as a time machine for your project, letting you rewind, compare, and learn from the past.</p>
<p>But Git needs a home, and that's where <strong>GitHub</strong> comes in. It's a bustling online platform where developers host their Git repositories, share code, and collaborate on projects. Think of it as a vibrant marketplace for ideas, where you can showcase your work, find inspiration, and join forces with others to build amazing things.</p>
<p><strong>GitHub Actions</strong> is your personal code-butler provided by GitHub! This automation platform stitches tasks like building, testing, and deploying into seamless workflows, triggered by every push or pull request. Think "mini-robots" whirring through your project, leaving you free to focus on the creative spark. So, embrace the automation revolution, let GitHub Actions take the wheel, and watch your development process hum smoothly like a well-oiled machine.</p>
<h2 id="heading-what-is-github-actions">What is GitHub Actions</h2>
<p>Imagine you're baking a cake. You gather ingredients (your code), mix them (build it), check if it's yummy (test it), and finally share it with everyone (deploy it). But wouldn't you love robots to handle all the mixing and checking while you focus on frosting the masterpiece?</p>
<p>That's what GitHub Actions does! It's like a robot army for your code, automating repetitive tasks in your development process. You tell it what to do in simple steps, like "mix for 5 minutes" or "run all the tests," and it just gets it done, triggered by every new batch of code (code change, pull request). No more manual work, just smooth sailing from baking to dessert!</p>
<p>So, GitHub Actions is your personal kitchen assistant for coding, freeing you to be the creative chef and whip up amazing software!</p>
<h2 id="heading-learn-about-github-actions">Learn about GitHub Actions</h2>
<p>GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create <strong><em>workflows</em></strong> that build and test every pull request to your repository, or deploy merged pull requests to production.</p>
<p>Github actions triggered based on the workflows files, let's create a workflow.</p>
<ul>
<li><p>In your repository, create the <code>.github/workflows/</code> directory to store your workflow files.</p>
</li>
<li><p>In the <code>.github/workflows/</code> directory, create a new file called <code>learn-github-actions.yml</code> and add the following code.</p>
</li>
<li><pre><code class="lang-yaml">      <span class="hljs-attr">name:</span> <span class="hljs-string">learn-github-actions</span>
      <span class="hljs-attr">run-name:</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.actor</span> <span class="hljs-string">}}</span> <span class="hljs-string">is</span> <span class="hljs-string">learning</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Actions</span>
      <span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]
      <span class="hljs-attr">jobs:</span>
        <span class="hljs-attr">check-bats-version:</span>
          <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
          <span class="hljs-attr">steps:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
              <span class="hljs-attr">with:</span>
                <span class="hljs-attr">node-version:</span> <span class="hljs-string">'14'</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">bats</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">bats</span> <span class="hljs-string">-v</span>
</code></pre>
</li>
<li><p>Commit these changes and push them to your GitHub repository.</p>
</li>
</ul>
<p>Your new GitHub Actions workflow file is now installed in your repository and will run automatically each time someone pushes a change to the repository. To see the details about a workflow's execution history go to Actions tab from your repository and in the left sidebar, click the workflow you want to see.</p>
<p><img src="https://docs.github.com/assets/cb-15465/images/help/repository/actions-tab-global-nav-update.png" alt="Screenshot of the tabs for the &quot;github/docs&quot; repository. The &quot;Actions&quot; tab is highlighted with an orange outline." /></p>
<p>To help you understand how YAML syntax is used to create a workflow file, this section explains each line of the introduction's example:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Optional - The name of the workflow as it will appear in the "Actions" tab of the GitHub repository. If this field is omitted, the name of the workflow file will be used instead.</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">learn-github-actions</span>
<span class="hljs-comment"># Optional - The name for workflow runs generated from the workflow, which will appear in the list of workflow runs on your repository's "Actions" tab. This example uses an expression with the `github` context to display the username of the actor that triggered the workflow run. For more information, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#run-name)."</span>
<span class="hljs-attr">run-name:</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.actor</span> <span class="hljs-string">}}</span> <span class="hljs-string">is</span> <span class="hljs-string">learning</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Actions</span>

<span class="hljs-comment"># Specifies the trigger for this workflow. This example uses the `push` event, so a workflow run is triggered every time someone pushes a change to the repository or merges a pull request.  This is triggered by a push to every branch; for examples of syntax that runs only on pushes to specific branches, paths, or tags, see "[AUTOTITLE](/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore)."</span>
<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]

<span class="hljs-comment"># Groups together all the jobs that run in the `learn-github-actions` workflow.</span>
  <span class="hljs-attr">jobs:</span>

<span class="hljs-comment"># Defines a job named `check-bats-version`. The child keys will define properties of the job.</span>
  <span class="hljs-attr">check-bats-version:</span>

<span class="hljs-comment"># Configures the job to run on the latest version of an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "[AUTOTITLE](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on)"</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

<span class="hljs-comment"># Groups together all the steps that run in the `check-bats-version` job. Each item nested under this section is a separate action or shell script.</span>
    <span class="hljs-attr">steps:</span>

<span class="hljs-comment"># The `uses` keyword specifies that this step will run `v4` of the `actions/checkout` action. This is an action that checks out your repository onto the runner, allowing you to run scripts or other actions against your code (such as build and test tools). You should use the checkout action any time your workflow will use the repository's code.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

<span class="hljs-comment"># This step uses the `actions/setup-node@v3` action to install the specified version of the Node.js. (This example uses version 14.) This puts both the `node` and `npm` commands in your `PATH`.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">'14'</span>

<span class="hljs-comment"># The `run` keyword tells the job to execute a command on the runner. In this case, you are using `npm` to install the `bats` software testing package.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">bats</span>

<span class="hljs-comment"># Finally, you'll run the `bats` command with a parameter that outputs the software version.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">bats</span> <span class="hljs-string">-v</span>
</code></pre>
<p><strong>What can you do with Github Actions Actually</strong></p>
<p>Here is a list of task you can do with Github Actions and you can find a list of events from <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows">here</a>.</p>
<p><strong>Build and test your code:</strong></p>
<ul>
<li><p>Run your build scripts and tools (e.g., Maven, Gradle, npm)</p>
</li>
<li><p>Execute unit and integration tests</p>
</li>
<li><p>Perform code coverage analysis</p>
</li>
<li><p>Generate documentation</p>
</li>
</ul>
<p><strong>Deployment and release:</strong></p>
<ul>
<li><p>Deploy your code to various platforms (e.g., cloud providers, servers)</p>
</li>
<li><p>Automate release processes like tagging, versioning, and publishing</p>
</li>
<li><p>Trigger notifications on successful deployments</p>
</li>
<li><p>Rollback deployments in case of errors</p>
</li>
</ul>
<p><strong>Continuous Integration and Continuous Delivery (CI/CD):</strong></p>
<ul>
<li><p>Set up automated pipelines for your build, test, and deployment process</p>
</li>
<li><p>Trigger actions on every push, pull request, or schedule</p>
</li>
<li><p>Track the progress of your pipelines and visualize their status</p>
</li>
<li><p>Integrate with other CI/CD tools and platforms</p>
</li>
</ul>
<p><strong>Other automation tasks:</strong></p>
<ul>
<li><p>Run security scans and vulnerability checks</p>
</li>
<li><p>Manage project dependencies</p>
</li>
<li><p>Perform code formatting and linting</p>
</li>
<li><p>Send emails and notifications</p>
</li>
<li><p>Run database migrations</p>
</li>
<li><p>Back up your code repositories</p>
</li>
<li><p>Generate reports and dashboards</p>
</li>
<li><p>Interact with external APIs</p>
</li>
<li><p>Run actions on a schedule</p>
</li>
<li><p>... and much more!</p>
</li>
</ul>
<p>Okay, enough learning let's build something.</p>
<h2 id="heading-examples">Examples</h2>
<p>Here are some examples about Github Actions.</p>
<h3 id="heading-run-a-test">Run a test</h3>
<p>Imagine we have a react application, and every time we push a new changes we want to check that, the test is perfectly work or not.</p>
<p>So for this we should create a YAML file in the <code>.github/workflows</code> directory (e.g., <code>react-tests.yml</code>) and put the code below in the workflow file.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">React</span> <span class="hljs-string">Tests</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-number">20</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Push the changes in your Github repository and see the magic.</p>
<h3 id="heading-build-and-deploy">Build and deploy</h3>
<p>Okay let's make an application to build and deploy a javascript application to GitHub pages.</p>
<p>As before create a new file in your project at <code>.github/workflows/deploy.yml</code> and paste in the YAML below.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-comment"># Trigger the workflow every time you push to the `main` branch</span>
  <span class="hljs-comment"># Using a different branch name? Replace `main` with your branch’s name</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]
  <span class="hljs-comment"># Allows you to run this workflow manually from the Actions tab on GitHub.</span>
  <span class="hljs-attr">workflow_dispatch:</span>

<span class="hljs-comment"># Allow this job to clone the repo and create a page deployment</span>
<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
  <span class="hljs-attr">pages:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">id-token:</span> <span class="hljs-string">write</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">your</span> <span class="hljs-string">repository</span> <span class="hljs-string">using</span> <span class="hljs-string">git</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install,</span> <span class="hljs-string">build,</span> <span class="hljs-string">and</span> <span class="hljs-string">upload</span> <span class="hljs-string">your</span> <span class="hljs-string">site</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">withastro/action@v1</span>
        <span class="hljs-comment"># with:</span>
          <span class="hljs-comment"># path: . # The root location of your Astro project inside the repository. (optional)</span>
          <span class="hljs-comment"># node-version: 18 # The specific version of Node that should be used to build your site. Defaults to 18. (optional)</span>
          <span class="hljs-comment"># package-manager: pnpm@latest # The Node package manager that should be used to install dependencies and build your site. Automatically detected based on your lockfile. (optional)</span>

  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">needs:</span> <span class="hljs-string">build</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">github-pages</span>
      <span class="hljs-attr">url:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.deployment.outputs.page_url</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">deployment</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/deploy-pages@v1</span>
</code></pre>
<p>Your site should now be published! When you push changes to your Astro project’s repository, the GitHub Action will automatically deploy them for you.</p>
<h3 id="heading-deploy-and-run-actions-on-server">Deploy and run actions on server</h3>
<p>Now let's create a deployment actions for a PHP (Laravel) application.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">DO</span>

<span class="hljs-comment"># Trigger the workflow on push and</span>
<span class="hljs-comment"># pull request events on the production branch</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-comment"># Authenticate to the the server via ssh</span>
<span class="hljs-comment"># and run our deployment script</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">server</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">appleboy/ssh-action@master</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">host:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.HOST</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">username:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.USERNAME</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">port:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.PORT</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">password:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.PASSWORD</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            cd /var/www/taksme
            source ~/.nvm/nvm.sh
            sh ./deploy.sh</span>
</code></pre>
<p>To run this you have to need set some env variables in your GitHub repository.</p>
<pre><code class="lang-bash">HOST=<span class="hljs-string">"ip-address-of-server"</span>
USERNAME=<span class="hljs-string">"deploy-user"</span>
PORT=<span class="hljs-string">"21"</span> <span class="hljs-comment"># by default 21, use your port of diff.</span>
PASSWORD=<span class="hljs-string">"user-password"</span>
</code></pre>
<p>You can find Digital Ocean deployment article from <a target="_blank" href="https://blog.msar.me/deploy-your-laravel-app-to-cloud-server">here</a>.</p>
<h3 id="heading-run-a-schedular">Run a schedular</h3>
<p>This is an interesting actions, this workflow generate a GitHub contribution graph as animation in your repository.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">gitartwork</span> <span class="hljs-string">from</span> <span class="hljs-string">a</span> <span class="hljs-string">contribution</span> <span class="hljs-string">graph</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
  <span class="hljs-attr">schedule:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">'* */24 * * *'</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Make</span> <span class="hljs-string">gitartwork</span> <span class="hljs-string">SVG</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">jasineri/gitartwork@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-comment"># Use this username's contribution graph</span>
          <span class="hljs-attr">user_name:</span> <span class="hljs-string">4msar</span>
          <span class="hljs-comment"># Text on contribution graph</span>
          <span class="hljs-attr">text:</span> <span class="hljs-string">MSAR</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">jasineri/simple-push-action@v1</span>
</code></pre>
<p>This actions will trigger everyday at 12:00 AM and generate a artwork like below.</p>
<p><img src="https://github.com/4msar/4msar/raw/master/gitartwork.svg" alt class="image--center mx-auto" /></p>
<p>Okay, hope you enjoy the examples and got an idea what you can do with GitHub actions.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, GitHub Actions stands as a transformative tool in the world of software development, emerging as a secret weapon for streamlining workflows, automating tasks, and fostering collaboration within teams.</p>
<p>Its seamless integration with the GitHub ecosystem empowers developers to create, customize, and deploy workflows that suit their unique project needs. The versatility and flexibility of Actions not only enhance productivity but also elevate the overall quality of software by enabling continuous integration, testing, and deployment.</p>
<p>Embracing GitHub Actions isn't just adopting a tool; it's embracing a culture of efficiency, innovation, and collaborative development in the modern software landscape.</p>
<hr />
<h4 id="heading-resources">Resources</h4>
<ul>
<li><p><a target="_blank" href="https://github.com/features/actions">https://github.com/features/actions</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/actions">https://github.com/actions</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/marketplace?type=actions">https://github.com/marketplace?type=actions</a></p>
</li>
<li><p><a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions">https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions</a></p>
</li>
<li><p><strong>Checkout my</strong> <a target="_blank" href="https://github.com/4msar/">GitHub Profile</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Testing in Laravel]]></title><description><![CDATA[Laravel's robust framework caters to a developer's desire for efficiency and elegance. But what about assurance, the quiet confidence that your code won't crumble under real-world pressure? That's where testing becomes your knight in shining armor.
T...]]></description><link>https://blog.msar.me/testing-in-laravel</link><guid isPermaLink="true">https://blog.msar.me/testing-in-laravel</guid><category><![CDATA[Feature Testing]]></category><category><![CDATA[Pest PHP]]></category><category><![CDATA[Laravel]]></category><category><![CDATA[Testing]]></category><category><![CDATA[PHP]]></category><category><![CDATA[PHPUnit]]></category><category><![CDATA[pestphp]]></category><category><![CDATA[unit testing]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Sat, 23 Dec 2023 14:48:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/IFpQtennlj8/upload/c7f581d0d64b04ce4eb2c020d5d4a712.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Laravel's robust framework caters to a developer's desire for efficiency and elegance. But what about <strong>assurance</strong>, the quiet confidence that your code won't crumble under real-world pressure? That's where <strong>testing</strong> becomes your knight in shining armor.</p>
<p><strong>The Power of Tests</strong></p>
<p>Testing isn't simply about catching bugs; it's about preventing them. By simulating user interactions and various scenarios, you proactively identify potential flaws, ensuring predictable, consistent behavior.</p>
<p>Laravel is built with testing in mind. In fact, support for testing with PHPUnit is included out of the box and a <code>phpunit.xml</code> file is already set up for your application. The framework also ships with convenient helper methods that allow you to expressively test your applications.</p>
<h2 id="heading-phpunit-testing-tool">PHPUnit Testing tool</h2>
<p><a target="_blank" href="http://phpunit.de/">PHPUnit</a> is one of the oldest and most well-known unit testing packages for PHP. It is primarily designed for unit testing, which means testing your code in the smallest components possible, but it is also incredibly flexible and can be used for a lot more than just unit testing. Moreover, it supports all major PHP frameworks including Laravel.</p>
<p>PHPUnit is developed with simple assertions, which make it pretty easier for you to test codes completely. Further it gives optimum results when you are testing code components individually, giving you magnified results, so that errors can be figure out easily. However, this means that testing much more advanced components like controllers, models and form validations can be a bit complicated as well.</p>
<p>In your newly installed Laravel application, you will find two files in the ./tests/ directory, one of <strong>ExampleTest.php</strong> and the other <strong>TestCase.php</strong>. TestCase.php file is basically a bootstrap file which sets the Laravel environment and features within our tests. It makes easy to use Laravel features in tests, and also enables framework for the testing helpers. The ExampleTest.php constitutes an example test class which contains basic test case using app testing helpers.</p>
<p>For creating new test class, you can either create a new file manually, or can run the inbuilt <strong>artisan make:test</strong> command of the Laravel.</p>
<p>Before running the test you should update the test environment in <code>.env.testing</code> file or <code>phpunit.xml</code> file.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_CONNECTION"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"sqlite"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"DB_DATABASE"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">":memory:"</span>/&gt;</span>
</code></pre>
<p>Let's create a test by running this command on your terminal.<br /><code>php artisan make:test BasicTest</code> it will create a test file in ./tests/ directory.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment"># test/Feature/BasicTest.php</span>

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Tests</span>\<span class="hljs-title">Feature</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Testing</span>\<span class="hljs-title">RefreshDatabase</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Testing</span>\<span class="hljs-title">WithFaker</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Tests</span>\<span class="hljs-title">TestCase</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BasicTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span>
</span>{
    <span class="hljs-comment">/**
     * A basic feature test example.
     *
     * <span class="hljs-doctag">@return</span> void
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">test_example</span>(<span class="hljs-params"></span>)
    </span>{
        $response = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'/'</span>);

        $response-&gt;assertStatus(<span class="hljs-number">200</span>);
    }
}
</code></pre>
<p>You can create multiple method for your test class, individual method behave like a individual test case. Okay, now run the tests.</p>
<pre><code class="lang-bash">php artisan <span class="hljs-built_in">test</span>
</code></pre>
<p>You will see a output like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703340976872/02834de4-e4ed-4eca-a92b-e34330d8d8f8.png" alt class="image--center mx-auto" /></p>
<p><strong><em>Given, When, Then in Testing</em></strong></p>
<p>If you want to test particular functions of your code, then you should follow the intrinsic pattern of Given, When and Then.</p>
<p><strong>Given</strong> – It states the initial environment setup you would like to test. You can use some data, or can even setup a model factory in this step.</p>
<p><strong>When</strong> – When refers to test specific function/method and called at some particular stage of the testing process.</p>
<p><strong>Then</strong> – In this part, you declare about the result how it should look like.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span> 
<span class="hljs-comment">// ...</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testStartsWithALetter</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-comment"># Given</span>
        $box = <span class="hljs-keyword">new</span> Box([<span class="hljs-string">'toy'</span>, <span class="hljs-string">'torch'</span>, <span class="hljs-string">'ball'</span>, <span class="hljs-string">'cat'</span>, <span class="hljs-string">'tissue'</span>]);

        <span class="hljs-comment"># When</span>
        $results = $box-&gt;startsWith(<span class="hljs-string">'t'</span>);

        <span class="hljs-comment"># Then</span>
        <span class="hljs-keyword">$this</span>-&gt;assertCount(<span class="hljs-number">3</span>, $results);
        <span class="hljs-keyword">$this</span>-&gt;assertContains(<span class="hljs-string">'toy'</span>, $results);
        <span class="hljs-keyword">$this</span>-&gt;assertContains(<span class="hljs-string">'torch'</span>, $results);
        <span class="hljs-keyword">$this</span>-&gt;assertContains(<span class="hljs-string">'tissue'</span>, $results);

        <span class="hljs-comment">// Empty array if passed even</span>
        <span class="hljs-keyword">$this</span>-&gt;assertEmpty($box-&gt;startsWith(<span class="hljs-string">'s'</span>));
    }
</code></pre>
<p>There are some common assertion helper in PHPUnit</p>
<ol>
<li><p>assertTrue()</p>
</li>
<li><p>assertFalse()</p>
</li>
<li><p>assertEquals()</p>
</li>
<li><p>assertNull()</p>
</li>
<li><p>assertNotNull()</p>
</li>
<li><p>assertContains()</p>
</li>
<li><p>assertCount()</p>
</li>
<li><p>assertEmpty()</p>
</li>
<li><p>assertSame()</p>
</li>
<li><p>and etc, you can find all the assertion method <a target="_blank" href="https://docs.phpunit.de/en/9.6/assertions.html">here</a></p>
</li>
</ol>
<h2 id="heading-pest-testing-tool">Pest Testing tool</h2>
<p><a target="_blank" href="https://pestphp.com/">Pest</a> is a new testing PHP Framework developed by <a target="_blank" href="https://twitter.com/enunomaduro">Nuno Maduro</a>. While Pest itself is built on top of <a target="_blank" href="https://phpunit.readthedocs.io/en/9.0/index.html">PHPUnit</a>, the popular and widely adopted PHP testing framework, Pest aims to provide a better experience for writing tests. The philosophy is simple. Keep the TDD experience simple and elegant by providing expressive interfaces.</p>
<p><strong>Setting up Pest</strong></p>
<p>Installing Pest PHP Testing Framework is a simple process that can be completed in just a few steps. Before you begin, make sure you have PHP <code>8.1+</code> or higher installed on your system.</p>
<p><strong>The first step</strong> is to require Pest as a "dev" dependency in your project by running the following command on your command line.</p>
<pre><code class="lang-bash">composer require pestphp/pest --dev --with-all-dependencies
</code></pre>
<p><strong>Secondly</strong>, you'll need to initialize Pest in your current PHP project. This step will create a configuration file named <code>Pest.php</code> at the root level of your test suite, which will enable you to fine-tune your test suite later.</p>
<pre><code class="lang-bash">./vendor/bin/pest --init
</code></pre>
<p><strong>Finally</strong>, you can run your tests by executing the <code>pest</code> command.</p>
<pre><code class="lang-xml">./vendor/bin/pest
</code></pre>
<p>Let's create a Pest test by running this command.<br /><code>php artisan make:test HomepageTest --pest</code></p>
<p>it will create a test file for Pest</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

test(<span class="hljs-string">'example'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $response = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'/'</span>);

    $response-&gt;assertStatus(<span class="hljs-number">200</span>);
});
</code></pre>
<p>Now update the test case like this.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

it(<span class="hljs-string">'can display the homepage'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $response = <span class="hljs-keyword">$this</span>-&gt;get(<span class="hljs-string">'/'</span>);

    $response-&gt;assertStatus(<span class="hljs-number">200</span>);
});
</code></pre>
<p>Now run the test by <code>php artisan test</code> or <code>./vendor/bin/pest</code> you will see output like this below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703341578671/68fdedac-0ae9-4a8f-aabc-07691a2cca61.png" alt class="image--center mx-auto" /></p>
<p>Each test usually consists of three steps:</p>
<ol>
<li><p><strong>Prepare</strong> your test first (creating models from factories, other setup)</p>
</li>
<li><p><strong>Act</strong> – do the test, execute the code that is being tested</p>
</li>
<li><p><strong>Assert</strong> that the 'Act' step has had the intended consequences</p>
</li>
</ol>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Post</span>;

it(<span class="hljs-string">'can display a post on the homepage'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Prepare</span>
    $post = Post::factory()-&gt;create();

    <span class="hljs-comment">// Act</span>
    $response = <span class="hljs-keyword">$this</span>-&gt;get(route(<span class="hljs-string">'home'</span>));

    <span class="hljs-comment">// Assert</span>
    $response-&gt;assertOk();
});
</code></pre>
<p>Imagine we have a ToDo model and we are going to test the API endpoints so a full API testing example below.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">App</span>\<span class="hljs-title">Models</span>\<span class="hljs-title">Todo</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Foundation</span>\<span class="hljs-title">Testing</span>\<span class="hljs-title">RefreshDatabase</span>;

uses(Tests\TestCase::class, RefreshDatabase::class);

it(<span class="hljs-string">'does not create a to-do without a name field'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $response = <span class="hljs-keyword">$this</span>-&gt;postJson(<span class="hljs-string">'/api/todos'</span>, []);
    $response-&gt;assertStatus(<span class="hljs-number">422</span>);
});

it(<span class="hljs-string">'can create a to-do'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $attributes = Todo::factory()-&gt;raw();
    $response = <span class="hljs-keyword">$this</span>-&gt;postJson(<span class="hljs-string">'/api/todos'</span>, $attributes);
    $response-&gt;assertStatus(<span class="hljs-number">201</span>)-&gt;assertJson([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Todo has been created'</span>]);
    <span class="hljs-keyword">$this</span>-&gt;assertDatabaseHas(<span class="hljs-string">'todos'</span>, $attributes);
});

it(<span class="hljs-string">'can fetch a to-do'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $todo = Todo::factory()-&gt;create();

    $response = <span class="hljs-keyword">$this</span>-&gt;getJson(<span class="hljs-string">"/api/todos/<span class="hljs-subst">{$todo-&gt;id}</span>"</span>);

    $data = [
        <span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'Retrieved To-do'</span>,
        <span class="hljs-string">'todo'</span> =&gt; [
            <span class="hljs-string">'id'</span> =&gt; $todo-&gt;id,
            <span class="hljs-string">'name'</span> =&gt; $todo-&gt;name,
            <span class="hljs-string">'completed'</span> =&gt; $todo-&gt;completed,
        ]
    ];

    $response-&gt;assertStatus(<span class="hljs-number">200</span>)-&gt;assertJson($data);
});

it(<span class="hljs-string">'can update a to-do'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $todo = Todo::factory()-&gt;create();
    $updatedTodo = [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'Updated To-do'</span>];
    $response = <span class="hljs-keyword">$this</span>-&gt;putJson(<span class="hljs-string">"/api/todos/<span class="hljs-subst">{$todo-&gt;id}</span>"</span>, $updatedTodo);
    $response-&gt;assertStatus(<span class="hljs-number">200</span>)-&gt;assertJson([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'To-do has been updated'</span>]);
    <span class="hljs-keyword">$this</span>-&gt;assertDatabaseHas(<span class="hljs-string">'todos'</span>, $updatedTodo);
});

it(<span class="hljs-string">'can delete a to-do'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $todo = Todo::factory()-&gt;create();
    $response = <span class="hljs-keyword">$this</span>-&gt;deleteJson(<span class="hljs-string">"/api/todos/<span class="hljs-subst">{$todo-&gt;id}</span>"</span>);
    $response-&gt;assertStatus(<span class="hljs-number">200</span>)-&gt;assertJson([<span class="hljs-string">'message'</span> =&gt; <span class="hljs-string">'To-do has been deleted'</span>]);
    <span class="hljs-keyword">$this</span>-&gt;assertCount(<span class="hljs-number">0</span>, Todo::all());
});
</code></pre>
<p>And the output for this test.</p>
<p><img src="https://assets.cdn.prod.twilio.com/images/OPdlmiAOuY_CLL-Il8OIkuraxTRgc9In8K2iAqc9pwGUk1.width-800.png" alt="Full set of unit tests passing" /></p>
<p><strong>Expectation API</strong></p>
<p>Now comes the interesting part, where Pest really stands apart from PHPUnit. In the above examples we used the <code>$this-&gt;assertSame(...)</code> methods to do an assertion. Pest also offers the so-called <strong>Expectation API</strong>, where you can <strong>write tests as if they were plain English</strong>. Let's refactor the previous example to use expectations:</p>
<pre><code class="lang-php">it(<span class="hljs-string">'is a dummy test'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $post = Post::factory()-&gt;create([<span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'Hello'</span>]);

    $title = $post-&gt;title;

    expect($title)-&gt;toBe(<span class="hljs-string">'Hello'</span>);
});
</code></pre>
<p>You can test your title also by writing this way,</p>
<pre><code class="lang-php">it(<span class="hljs-string">'is a dummy test'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $post = Post::factory()-&gt;create([<span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'Hello'</span>]);

    expect($post)
        -&gt;title
        -&gt;toBe(<span class="hljs-string">'Hello'</span>);
});

<span class="hljs-comment">// You can also chain multiple Higher Order expectations</span>
it(<span class="hljs-string">'is a dummy test'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    $post = Post::factory()-&gt;create([<span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'Hello'</span>]);

    expect($post)
        -&gt;title-&gt;toBe(<span class="hljs-string">'Hello'</span>)
        -&gt;body-&gt;toBeNull();
});
</code></pre>
<p>You can also write our own <strong>custom Pest expectation</strong> by using the <code>expect()-&gt;extend(...)</code> function. See the following example from the Pest docs:</p>
<pre><code class="lang-php">expect()-&gt;extend(<span class="hljs-string">'toBeWithinRange'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$min, $max</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>
       -&gt;toBeGreaterThanOrEqual($min)
       -&gt;toBeLessThanOrEqual($max);
});

test(<span class="hljs-string">'numeric ranges'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    expect(<span class="hljs-number">100</span>)-&gt;toBeWithinRange(<span class="hljs-number">90</span>, <span class="hljs-number">110</span>);
});
</code></pre>
<h2 id="heading-conclusion-a-code-of-confidence">Conclusion: A Code of Confidence</h2>
<p>Your journey to mastering Laravel testing isn't just about learning tools; it's about cultivating a <strong>developer's superpower - the unwavering confidence that your code will shine</strong>. Each executed test becomes a brick in the fortress of your application, protecting it from the unpredictable winds of real-world use.</p>
<p>So, embrace the test-driven mantra. Let curiosity be your compass, experiment be your fuel, and the Laravel community your support system. As you navigate the exciting landscape of testing, remember that the true reward isn't just bug-free code, but the <strong>empowerment to build software that stands tall, whispers quality, and roars with reliability.</strong></p>
<p>Take the first step today. Pick up your keyboard, write your first test, and watch your confidence soar as you master the art of Laravel testing.</p>
<h4 id="heading-resources"><strong>Resources</strong></h4>
<ul>
<li><p><a target="_blank" href="https://laravel.com/docs/10.x/testing">https://laravel.com/docs/10.x/testing</a></p>
</li>
<li><p><a target="_blank" href="https://docs.phpunit.de/en/9.6/assertions.html">https://docs.phpunit.de/en/9.6/assertions.html</a></p>
</li>
<li><p><a target="_blank" href="https://pestphp.com/docs/installation">https://pestphp.com/docs</a></p>
</li>
<li><p><a target="_blank" href="https://ralphjsmit.com/pest-php-testing-laravel">https://ralphjsmit.com/pest-php-testing-laravel</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Asynchronous Programming with Promises and Async/Await in JavaScript]]></title><description><![CDATA[JavaScript's ability to handle multiple tasks simultaneously, known as asynchronous programming, is what makes it so powerful. But this power comes with complexity. Enter Promises and Async/Await, two tools that transform the landscape of asynchronou...]]></description><link>https://blog.msar.me/asynchronous-programming-with-promises-and-async-await-in-javascript</link><guid isPermaLink="true">https://blog.msar.me/asynchronous-programming-with-promises-and-async-await-in-javascript</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[asynchronous JavaScript]]></category><category><![CDATA[promises]]></category><category><![CDATA[async/await]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Mon, 18 Dec 2023 18:42:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702924897186/79958745-25a1-4a09-8079-c47184d043ad.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JavaScript's ability to handle multiple tasks simultaneously, known as asynchronous programming, is what makes it so powerful. But this power comes with complexity. Enter Promises and Async/Await, two tools that transform the landscape of asynchronous coding, making it cleaner, more readable, and ultimately, more enjoyable.</p>
<h2 id="heading-the-callback-catastrophe-a-javascript-horror-story"><strong>The Callback Catastrophe: A JavaScript Horror Story</strong></h2>
<p>Before Promises, callbacks were the only way to handle asynchronous operations. Imagine you're trying to bake a cake. You ask your friend to mix the batter (the asynchronous function), and you give them a callback (a function) to run with the results (the mixed batter). But then you need to wait for the eggs to boil (another asynchronous function), and you need to pass another callback to handle those results and so on.</p>
<p>This quickly leads to "<mark>callback hell</mark>," a nested structure of functions that becomes difficult to track and debug. Imagine the cake recipe with callbacks:</p>
<pre><code class="lang-javascript">mixBatter(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">batter</span>) </span>{
  boilEggs(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">eggs</span>) </span>{
    creamButter(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">creamedButter</span>) </span>{
      combineIngredients(batter, eggs, creamedButter, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">cake</span>) </span>{
        bakeCake(cake, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">bakedCake</span>) </span>{
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Delicious cake is ready!"</span>);
        });
      });
    });
  });
});
</code></pre>
<p>This spaghetti code makes it hard to follow the flow of execution and identify errors. Debugging becomes a nightmare, like searching for a specific ingredient in a messy pantry.</p>
<h2 id="heading-promises-knights-in-shining-armor"><strong>Promises: Knights in Shining Armor</strong></h2>
<p>Promises come to the rescue, offering a clear and structured way to handle asynchronous operations. Imagine them as envelopes you send containing your instructions and a placeholder for the eventual results. You give the envelope to the asynchronous function (your friend with the mixer), and when they're done, they fill the envelope with the mixed batter and send it back. You can then open the envelope (using the <code>then</code> method) and use the results (the batter) to continue baking.</p>
<p>Promises make your code much cleaner and easier to read. No more nesting callbacks! You can chain multiple asynchronous operations one after another using <code>then</code>, creating a clear flow of execution:</p>
<pre><code class="lang-javascript">mixBatter().then(<span class="hljs-function"><span class="hljs-params">batter</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> boilEggs();
}).then(<span class="hljs-function"><span class="hljs-params">eggs</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> creamButter();
}).then(<span class="hljs-function"><span class="hljs-params">creamedButter</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> combineIngredients(batter, eggs, creamedButter);
}).then(<span class="hljs-function"><span class="hljs-params">cake</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> bakeCake(cake);
}).then(<span class="hljs-function"><span class="hljs-params">bakedCake</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Delicious cake is ready!"</span>);
});
</code></pre>
<p>The code reads just like the recipe steps, one after another, making it much easier to understand and debug. So, no more callback chains stretching across your code like vines! With Promises, you can:</p>
<ul>
<li><p><strong>Write cleaner code:</strong> Instead of juggling callbacks, you use <code>then</code> and <code>catch</code> methods to handle successful results and errors, respectively.</p>
</li>
<li><p><strong>Chain operations with ease:</strong> <code>then</code> allows you to seamlessly link multiple asynchronous tasks, one after the other.</p>
</li>
<li><p><strong>Improve error handling:</strong> <code>catch</code> provides a central location to deal with any issues that may arise during asynchronous operations.</p>
</li>
</ul>
<h2 id="heading-asyncawait-the-code-whisperer"><strong>Async/Await: The Code Whisperer</strong></h2>
<p>While Promises improve asynchronous code, Async/Await takes it to another level. Imagine being able to write asynchronous code as if it were synchronous! That's exactly what Async/Await allows you to do.</p>
<p>Simply mark a function as <code>async</code>, and you can use the <code>await</code> keyword before any Promise-returning function. The magic happens here: instead of waiting for the Promise to resolve and then continuing, the execution will simply pause at that point. When the Promise is resolved, the value within the Promise will be assigned to a variable for you to use further.</p>
<p>This makes your code look incredibly clean and linear. It reads almost like a step-by-step recipe, each <code>await</code> marking a point where you wait for something to happen before moving on:</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">bakeCake</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> batter = <span class="hljs-keyword">await</span> mixBatter();
  <span class="hljs-keyword">const</span> eggs = <span class="hljs-keyword">await</span> boilEggs();
  <span class="hljs-keyword">const</span> creamedButter = <span class="hljs-keyword">await</span> creamButter();
  <span class="hljs-keyword">const</span> cake = <span class="hljs-keyword">await</span> combineIngredients(batter, eggs, creamedButter);
  <span class="hljs-keyword">const</span> bakedCake = <span class="hljs-keyword">await</span> bakeCake(cake);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Delicious cake is ready!"</span>);
}

bakeCake();
</code></pre>
<p>Async/Await is your cartographer, allowing you to write code as if it were synchronous, even when dealing with asynchronous operations.</p>
<p>Here's the magic:</p>
<ul>
<li><p><strong>Mark functions as</strong> <code>async</code>: This tells the compiler that the function might contain asynchronous operations.</p>
</li>
<li><p><strong>Use the</strong> <code>await</code> keyword: This keyword indicates a point where you want to wait for a Promise to resolve before moving on.</p>
</li>
<li><p><strong>The code pauses and waits</strong>: While waiting for the Promise, the rest of the code execution is paused, giving you a linear flow.</p>
</li>
</ul>
<h2 id="heading-beyond-the-basics-advanced-techniques">Beyond the Basics: Advanced Techniques</h2>
<p>Promises and Async/Await offer even more power beyond the basic examples. You can chain multiple asynchronous operations together using <code>then</code> and <code>await</code> in sequence, handle parallel tasks with <code>Promise.all</code>, and even use techniques like error handling and cancellation for robust and reliable asynchronous code.</p>
<p>Here are some examples of advanced techniques you can explore with Promises and Async/Await in JavaScript:</p>
<p><strong>1. Chaining Promises with Error Handling:</strong></p>
<p>Imagine fetching data from multiple APIs in sequence, where each step depends on the successful completion of the previous one. You can chain Promises with <code>then</code> and <code>catch</code> to handle errors and gracefully propagate them throughout the chain:</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">fetchDataChain</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/users/123'</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> user.json();
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`/api/posts/<span class="hljs-subst">${data.id}</span>`</span>);
    <span class="hljs-keyword">const</span> postList = <span class="hljs-keyword">await</span> posts.json();
    <span class="hljs-comment">// Use postList data</span>
    <span class="hljs-keyword">return</span> postList;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    <span class="hljs-comment">// Handle error gracefully and possibly return a fallback value</span>
  }
}

fetchDataChain().then(<span class="hljs-function"><span class="hljs-params">postList</span> =&gt;</span> {
  <span class="hljs-comment">// Do something with the post list</span>
}).catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
  <span class="hljs-comment">// Handle any errors from the chain</span>
});
</code></pre>
<p><strong>2. Parallel Execution with Promise.all:</strong></p>
<p>Sometimes you need to perform multiple asynchronous operations simultaneously, like fetching data from several APIs at once. <code>Promise.all</code> allows you to wait for all promises in an array to resolve and then access the results as a single array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> promises = [
  fetch(<span class="hljs-string">'/api/products/1'</span>),
  fetch(<span class="hljs-string">'/api/products/2'</span>),
  fetch(<span class="hljs-string">'/api/products/3'</span>),
];

<span class="hljs-built_in">Promise</span>.all(promises)
  .then(<span class="hljs-function"><span class="hljs-params">responses</span> =&gt;</span> <span class="hljs-built_in">Promise</span>.all(responses.map(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())))
  .then(<span class="hljs-function"><span class="hljs-params">products</span> =&gt;</span> {
    <span class="hljs-comment">// Process all product data together</span>
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(error);
  });
</code></pre>
<p><strong>3. Error Cancelling with AbortController:</strong></p>
<p>Imagine fetching data from a slow API but needing to cancel the request if the user navigates away from the page. <code>AbortController</code> allows you to create a signal that can be used to cancel an ongoing asynchronous operation:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();
<span class="hljs-keyword">const</span> signal = controller.signal;

fetch(<span class="hljs-string">'/api/large-data'</span>, { signal })
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-comment">// Use the data</span>
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (error.name === <span class="hljs-string">'AbortError'</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Request cancelled'</span>);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(error);
    }
  });

<span class="hljs-comment">// On user navigation, cancel the request</span>
controller.abort();
</code></pre>
<p>These are just a few examples to spark your exploration of advanced techniques with Promises and Async/Await. Remember, the possibilities are endless! By mastering these tools and experimenting with their capabilities, you can build robust, efficient, and enjoyable asynchronous applications in JavaScript.</p>
<p><strong>The Synergistic Duo: Promises and Async/Await, Hand in Hand</strong></p>
<p>Promises and Async/Await are best friends. Promises provide the underlying mechanism for handling asynchronous operations, while Async/Await simplifies their usage with a more synchronous-like syntax. They work together seamlessly, making asynchronous programming in JavaScript an enjoyable and productive experience.</p>
<p><strong>Resources:</strong></p>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise MDN docs</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous">Asynchronous JavaScript</a></p>
</li>
<li><p><a target="_blank" href="https://javascript.info/promise-api">Promise API</a></p>
</li>
<li><p><a target="_blank" href="https://eloquentjavascript.net/11_async.html">Eloquent JavaScript</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Securing Laravel Applications with Advanced Authentication and Authorization Strategies]]></title><description><![CDATA[In today's digital landscape, security is paramount, and Laravel applications are no exception. With sensitive user data and critical business logic at stake, implementing robust authentication and authorization strategies is crucial for ensuring you...]]></description><link>https://blog.msar.me/securing-laravel-applications-with-advanced-authentication-and-authorization-strategies</link><guid isPermaLink="true">https://blog.msar.me/securing-laravel-applications-with-advanced-authentication-and-authorization-strategies</guid><category><![CDATA[Laravel]]></category><category><![CDATA[authentication]]></category><category><![CDATA[authorization]]></category><category><![CDATA[Security]]></category><category><![CDATA[2FA]]></category><category><![CDATA[Roles Permission]]></category><category><![CDATA[Policy]]></category><category><![CDATA[Laravel Sanctum]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Thu, 14 Dec 2023 10:10:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/U_aWVtT2JRA/upload/51f2bcab4209220bb941f20343ffca91.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's digital landscape, security is paramount, and Laravel applications are no exception. With sensitive user data and critical business logic at stake, implementing robust authentication and authorization strategies is crucial for ensuring your Laravel application remains secure. This article delves into advanced techniques to fortify your application against unauthorized access and vulnerabilities.</p>
<h2 id="heading-beyond-basic-authentication">Beyond Basic Authentication:</h2>
<p>Laravel's built-in authentication features provide a solid foundation, but for enhanced security, consider implementing advanced strategies:</p>
<h3 id="heading-password-hashing-and-salting">Password Hashing and Salting:</h3>
<p>Store user passwords securely using strong hashing algorithms like Bcrypt, and combine them with unique salts for additional protection. This mitigates the risk of password breaches and rainbow table attacks.</p>
<h4 id="heading-example-of-password-hashing-and-salting-in-laravel">Example of Password Hashing and Salting in Laravel</h4>
<p>Here's an example of password hashing and salting in Laravel:</p>
<p><strong>1. Hashing a Password:</strong></p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Hash</span>;

$password = <span class="hljs-string">"password123"</span>; <span class="hljs-comment">// User's input password</span>

<span class="hljs-comment">// Hash the password with Bcrypt algorithm</span>
$hashedPassword = Hash::make($password);

<span class="hljs-comment">// Store the hashed password in the database</span>
User::create([
    <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'John Doe'</span>,
    <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john.doe@example.com'</span>,
    <span class="hljs-string">'password'</span> =&gt; $hashedPassword,
]);
</code></pre>
<p><strong>2. Verifying a Password:</strong></p>
<pre><code class="lang-php">$user = User::where(<span class="hljs-string">'email'</span>, <span class="hljs-string">'john.doe@example.com'</span>)-&gt;first();

$password = <span class="hljs-string">"password123"</span>; <span class="hljs-comment">// User's input password</span>

<span class="hljs-comment">// Verify the password against the stored hash</span>
<span class="hljs-keyword">if</span> (Hash::check($password, $user-&gt;password)) {
    <span class="hljs-comment">// Password is valid</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Login successful"</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Password is invalid</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Invalid password"</span>;
}
</code></pre>
<p><strong>3. Salting the Password:</strong></p>
<p>By default, Laravel automatically generates a random salt when hashing passwords. However, you can also manually create and store the salt separately if needed.</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Str</span>;

$password = <span class="hljs-string">"password123"</span>;
$salt = Str::random(<span class="hljs-number">32</span>); <span class="hljs-comment">// Generate a random salt</span>

$hashedPassword = Hash::make($password, [<span class="hljs-string">'rounds'</span> =&gt; <span class="hljs-number">12</span>, <span class="hljs-string">'salt'</span> =&gt; $salt]); <span class="hljs-comment">// Hash with custom rounds</span>

<span class="hljs-comment">// Store the hashed password and salt in the database</span>
User::create([
    <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'John Doe'</span>,
    <span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john.doe@example.com'</span>,
    <span class="hljs-string">'password'</span> =&gt; $hashedPassword,
    <span class="hljs-string">'salt'</span> =&gt; $salt,
]);
</code></pre>
<p><strong>4. Verifying a Salted Password:</strong></p>
<pre><code class="lang-php">$user = User::where(<span class="hljs-string">'email'</span>, <span class="hljs-string">'john.doe@example.com'</span>)-&gt;first();

$password = <span class="hljs-string">"password123"</span>;
$salt = $user-&gt;salt; <span class="hljs-comment">// Retrieve the stored salt</span>

$hashedPassword = Hash::make($password, [<span class="hljs-string">'rounds'</span> =&gt; <span class="hljs-number">12</span>, <span class="hljs-string">'salt'</span> =&gt; $salt]); <span class="hljs-comment">// Hash with the stored salt</span>

<span class="hljs-comment">// Verify the password against the stored hash</span>
<span class="hljs-keyword">if</span> (Hash::check($password, $user-&gt;password)) {
    <span class="hljs-comment">// Password is valid</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Login successful"</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Password is invalid</span>
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Invalid password"</span>;
}
</code></pre>
<p>This example demonstrates how to hash and salt passwords in Laravel using the <code>Hash</code> facade. Remember to choose a strong hashing algorithm like Bcrypt and use appropriate salt generation techniques for optimal security.</p>
<h3 id="heading-multi-factor-authentication-mfa">Multi-Factor Authentication (MFA):</h3>
<p>Implement MFA to add a layer of verification beyond just passwords. This can include codes sent via SMS, authenticator apps, or physical security tokens, significantly increasing the difficulty of unauthorized access.</p>
<p>Here is an example of the Google 2FA authentication process and implementation in laravel.</p>
<p><strong>Installing a 2FA package</strong></p>
<p>Use Composer to install it:</p>
<pre><code class="lang-bash">composer require pragmarx/google2fa-laravel
</code></pre>
<p>Publish the config file</p>
<pre><code class="lang-bash">php artisan vendor:publish --provider=<span class="hljs-string">"PragmaRX\Google2FALaravel\ServiceProvider"</span>
</code></pre>
<p>Generate the 2FA secret</p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Google2FA</span>;

<span class="hljs-keyword">return</span> Google2FA::generateSecretKey();
</code></pre>
<p><strong>Middleware</strong></p>
<p>This package has a middleware that will help you code 2FA on your app. To use it, you just have to:</p>
<p>Add the middleware to your Kernel.php:</p>
<pre><code class="lang-php"><span class="hljs-keyword">protected</span> $routeMiddleware = [
    ...
    <span class="hljs-string">'2fa'</span> =&gt; \PragmaRX\Google2FALaravel\Middleware::class,
];
</code></pre>
<p>Using it in one or more routes:</p>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/admin'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> view(<span class="hljs-string">'admin.index'</span>);
})-&gt;middleware([<span class="hljs-string">'auth'</span>, <span class="hljs-string">'2fa'</span>]);
</code></pre>
<p>For more details about this implementation, you can look at <a target="_blank" href="https://github.com/antonioribeiro/google2fa-laravel">this</a>.</p>
<h3 id="heading-secure-session-management">Secure Session Management:</h3>
<p>Utilize Laravel's session management features like session drivers and "remember me" functionality responsibly. Ensure sessions are protected from session hijacking attacks by utilizing secure cookies with HTTPS and setting appropriate timeouts.</p>
<p>Here's an example of implementing key practices:</p>
<p><strong>1. Configure Session Driver:</strong></p>
<ul>
<li><p>By default, Laravel uses file-based session storage. Consider using a more secure driver like database-based sessions for persistent data and increased security.</p>
</li>
<li><p>Configure the driver in <code>config/session.php</code>:</p>
</li>
</ul>
<pre><code class="lang-php"><span class="hljs-string">'driver'</span> =&gt; <span class="hljs-string">'database'</span>,

<span class="hljs-string">'database'</span> =&gt; [
    <span class="hljs-string">'table'</span> =&gt; <span class="hljs-string">'sessions'</span>,
],
</code></pre>
<p><strong>2. Secure Cookies:</strong></p>
<ul>
<li>Enable the <code>secure</code> and <code>http_only</code> attributes for session cookies to prevent eavesdropping and XSS attacks in <code>session.php</code> config:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-string">'secure'</span> =&gt; <span class="hljs-literal">true</span>,
<span class="hljs-string">'http_only'</span> =&gt; <span class="hljs-literal">true</span>,
</code></pre>
<p><strong>3. Set Session Lifetime:</strong></p>
<ul>
<li>Define a reasonable session lifetime to automatically log out users after inactivity to reduce the risk of unauthorized access:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-string">'lifetime'</span> =&gt; <span class="hljs-number">120</span>, <span class="hljs-comment">// Minutes</span>
</code></pre>
<p><strong>4. Use HTTPS:</strong></p>
<ul>
<li>Enforce HTTPS communication for all interactions between the user and the application to ensure data encryption in transit:</li>
</ul>
<pre><code class="lang-php">URL::forceScheme(<span class="hljs-string">'https'</span>);
</code></pre>
<p><strong>5. Implement Session Invalidation:</strong></p>
<ul>
<li>Invalidate user sessions on specific events like password changes or logout to ensure a secure user state:</li>
</ul>
<pre><code class="lang-php">Auth::logout();
</code></pre>
<p><strong>6. Use Session Middleware:</strong></p>
<ul>
<li>Implement session middleware to restrict access to specific routes only for authenticated users:</li>
</ul>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/admin'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// ...</span>
})-&gt;middleware(<span class="hljs-string">'auth'</span>);
</code></pre>
<p><strong>7. Remember Me Functionality:</strong></p>
<ul>
<li>Use Laravel's "remember me" functionality cautiously, ensuring appropriate cookie settings and secure storage for the remember-me token:</li>
</ul>
<pre><code class="lang-php">Auth::attempt([<span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'john@example.com'</span>, <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'password'</span>], <span class="hljs-literal">true</span>);
</code></pre>
<p>By implementing these best practices for secure session management in your Laravel application, you can significantly enhance user security and protect sensitive data from unauthorized access.</p>
<h3 id="heading-api-token-authentication">API Token Authentication:</h3>
<p>For API access, consider leveraging Laravel Sanctum. This package provides secure token-based authentication, offering granular control over access to specific resources and scopes.</p>
<blockquote>
<p><em>The most recent versions of Laravel already include Laravel Sanctum. However, if your application's composer.json file does not include laravel/sanctum, you may follow the installation instructions below.</em></p>
</blockquote>
<p><strong>1. Installation and Configuration:</strong></p>
<ul>
<li>Install the Laravel Sanctum package:</li>
</ul>
<pre><code class="lang-bash">composer require laravel/sanctum
</code></pre>
<ul>
<li>Publish the Sanctum configuration and migration files:</li>
</ul>
<pre><code class="lang-bash">php artisan vendor:publish --provider=<span class="hljs-string">"Laravel\Sanctum\SanctumServiceProvider"</span>
</code></pre>
<ul>
<li>Configure the <code>config/sanctum.php</code> file to activate Sanctum for your API routes.</li>
</ul>
<p><strong>2. Generate API Tokens:</strong></p>
<ul>
<li>Implement a controller method to generate API tokens for authenticated users:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createToken</span>(<span class="hljs-params">Request $request</span>)
</span>{
    $user = Auth::user();

    $token = $user-&gt;createToken(<span class="hljs-string">'api'</span>);

    <span class="hljs-keyword">return</span> response()-&gt;json([<span class="hljs-string">'token'</span> =&gt; $token-&gt;plainTextToken]);
}
</code></pre>
<ul>
<li>Store the generated token securely, for example, in a local storage or database.</li>
</ul>
<p><strong>3. Secure API Routes:</strong></p>
<ul>
<li>Protect your API routes by requiring an API token in the request header:</li>
</ul>
<pre><code class="lang-php">Route::group([<span class="hljs-string">'middleware'</span> =&gt; <span class="hljs-string">'auth:sanctum'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Your API routes</span>
});
</code></pre>
<p><strong>4. Token Abilities:</strong> Sanctum allows you to assign "abilities" to tokens. Abilities serve a similar purpose as OAuth's "scopes". You may pass an array of string abilities as the second argument to the <code>createToken</code> method:</p>
<pre><code class="lang-php"><span class="hljs-keyword">return</span> $user-&gt;createToken(<span class="hljs-string">'token-name'</span>, [<span class="hljs-string">'server:update'</span>])-&gt;plainTextToken;
</code></pre>
<p>You may then verify that a token has a given ability using the <code>tokenCan</code> method:</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> ($user-&gt;tokenCan(<span class="hljs-string">'server:update'</span>)) {
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>You may also determine if a token is missing a given ability using the ability middleware:</p>
<pre><code class="lang-php"><span class="hljs-string">'abilities'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
<span class="hljs-string">'ability'</span> =&gt; \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
</code></pre>
<p>Once the middleware has been registered, you may assign it to a route or a group of routes:</p>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/orders'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Token has both "check-status" and "place-orders" abilities...</span>
})-&gt;middleware([<span class="hljs-string">'auth:sanctum'</span>, <span class="hljs-string">'abilities:check-status,place-orders'</span>]);
</code></pre>
<p>The <code>ability</code>` middleware may be assigned to a route to verify that the incoming request's token has at least one of the listed abilities:</p>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/orders'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Token has the "check-status" or "place-orders" ability...</span>
})-&gt;middleware([<span class="hljs-string">'auth:sanctum'</span>, <span class="hljs-string">'ability:check-status,place-orders'</span>]);
</code></pre>
<p><strong>5. Revoke API Tokens:</strong></p>
<ul>
<li>Implement methods in your user model to revoke specific or all API tokens:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">// Revoke all tokens...</span>
$user-&gt;tokens()-&gt;delete();

<span class="hljs-comment">// Revoke the token that was used to authenticate the current request...</span>
$request-&gt;user()-&gt;currentAccessToken()-&gt;delete();

<span class="hljs-comment">// Revoke a specific token...</span>
$user-&gt;tokens()-&gt;where(<span class="hljs-string">'id'</span>, $tokenId)-&gt;delete();
</code></pre>
<p>By implementing API token authentication, you can enhance the security and flexibility of your Laravel API and ensure that only authorized users can access your resources.</p>
<hr />
<h2 id="heading-authorization-granting-access-with-granularity">Authorization: Granting Access with Granularity:</h2>
<p>Beyond authentication, authorization controls what users can do within your application. Laravel offers powerful tools for implementing fine-grained access controls:</p>
<h3 id="heading-role-based-access-control-rbac">Role-Based Access Control (RBAC):</h3>
<p>Define user roles with specific permissions, assigning them to individual users or groups. This ensures users only access resources and perform actions authorized for their role.</p>
<p><strong>1. Define Roles and Permissions:</strong></p>
<ul>
<li>Create models for <code>Role</code> and <code>Permission</code>:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">// Role Model</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Role</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">permissions</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsToMany(Permission::class);
    }
}

<span class="hljs-comment">// Permission Model</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Permission</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Model</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">roles</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsToMany(Role::class);
    }
}
</code></pre>
<ul>
<li>Define roles and associated permissions in your database:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">// Roles</span>
DB::table(<span class="hljs-string">'roles'</span>)-&gt;insert([
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'admin'</span>],
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'editor'</span>],
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'user'</span>],
]);

<span class="hljs-comment">// Permissions</span>
DB::table(<span class="hljs-string">'permissions'</span>)-&gt;insert([
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'create posts'</span>],
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'edit posts'</span>],
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'publish posts'</span>],
    [<span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'manage users'</span>],
]);

<span class="hljs-comment">// Assign permissions to roles</span>
$adminRole = Role::where(<span class="hljs-string">'name'</span>, <span class="hljs-string">'admin'</span>)-&gt;first();
$adminRole-&gt;permissions()-&gt;attach([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]);

$editorRole = Role::where(<span class="hljs-string">'name'</span>, <span class="hljs-string">'editor'</span>)-&gt;first();
$editorRole-&gt;permissions()-&gt;attach([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>]);

$userRole = Role::where(<span class="hljs-string">'name'</span>, <span class="hljs-string">'user'</span>)-&gt;first();
$userRole-&gt;permissions()-&gt;attach(<span class="hljs-number">1</span>);
</code></pre>
<p><strong>2. Assign Roles to Users:</strong></p>
<ul>
<li>Define a relationship between <code>User</code> and <code>Role</code> models:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">// User Model</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Authenticatable</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">roles</span>(<span class="hljs-params"></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;belongsToMany(Role::class);
    }
}
</code></pre>
<ul>
<li>Assign roles to users:</li>
</ul>
<pre><code class="lang-php">$user = User::find(<span class="hljs-number">1</span>);
$user-&gt;roles()-&gt;attach(<span class="hljs-number">1</span>); <span class="hljs-comment">// Assign 'admin' role</span>
</code></pre>
<p><strong>3. Implement Authorization Checks:</strong></p>
<ul>
<li>Use Laravel's <code>Gate</code> class to define authorization checks based on roles and permissions:</li>
</ul>
<pre><code class="lang-php">Gate::define(<span class="hljs-string">'create-post'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">User $user</span>) </span>{
    <span class="hljs-keyword">return</span> $user-&gt;hasPermission(<span class="hljs-string">'create posts'</span>);
});

Gate::define(<span class="hljs-string">'edit-post'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">User $user</span>) </span>{
    <span class="hljs-keyword">return</span> $user-&gt;hasPermission(<span class="hljs-string">'edit posts'</span>);
});
</code></pre>
<ul>
<li>Utilize authorization checks in your controller methods to restrict access:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>)
</span>{
    <span class="hljs-keyword">if</span> (!Gate::allows(<span class="hljs-string">'create-post'</span>)) {
        abort(<span class="hljs-number">403</span>);
    }

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

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">edit</span>(<span class="hljs-params">Post $post</span>)
</span>{
    <span class="hljs-keyword">if</span> (!Gate::allows(<span class="hljs-string">'edit-post'</span>, $post)) {
        abort(<span class="hljs-number">403</span>);
    }

    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><strong>4. Middleware for Role-Based Access Control:</strong></p>
<ul>
<li>Create middleware to enforce authorization based on roles:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthorizeRoleMiddleware</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params">Request $request, <span class="hljs-built_in">Closure</span> $next, ...$roles</span>)
    </span>{
        <span class="hljs-keyword">if</span> (!Auth::user()-&gt;hasRole($roles)) {
            abort(<span class="hljs-number">403</span>);
        }

        <span class="hljs-keyword">return</span> $next($request);
    }
}
</code></pre>
<ul>
<li>Apply the middleware to specific routes:</li>
</ul>
<pre><code class="lang-php">Route::group([<span class="hljs-string">'middleware'</span> =&gt; AuthorizeRoleMiddleware::class], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Routes requiring admin role</span>
});
</code></pre>
<p><strong>Additional Resources:</strong></p>
<ul>
<li><p>Laravel Gate documentation: <a target="_blank" href="https://laravel.com/docs/10.x/authorization">https://laravel.com/docs/10.x/authorization</a></p>
</li>
<li><p>Implementing Role-Based Access Control in Laravel: <a target="_blank" href="https://ollieread.com/archive/read/laravel-rbac-role-based-access-control-without-over-engineering/">https://ollieread.com/archive/read/laravel-rbac-role-based-access-control-without-over-engineering/</a></p>
</li>
<li><p>Laravel Spatie Roles and Permissions: <a target="_blank" href="https://spatie.be/docs/laravel-permission/v6/basic-usage/role-permissions">https://spatie.be/docs/laravel-permission/v6/basic-usage/role-permissions</a></p>
</li>
</ul>
<p>By implementing RBAC in your Laravel application, you can ensure that users only access resources and functionalities permitted by their assigned roles, enhancing security and user experience.</p>
<h3 id="heading-policies">Policies:</h3>
<p>Leverage Laravel's policy system for more granular control. Create policies to define access permissions for specific models and resources, allowing for dynamic and context-aware authorization decisions.</p>
<p>Policies provide a flexible way to manage authorization logic in Laravel applications. Here's an example:</p>
<p><strong>1. Create a Policy:</strong></p>
<ul>
<li>Generate a policy for a specific model:</li>
</ul>
<pre><code class="lang-bash">php artisan make:policy PostPolicy --model=App\Models\Post
</code></pre>
<p>This command creates a policy class (<code>App\Policies\PostPolicy</code>) responsible for authorizing actions on the <code>Post</code> model.</p>
<p><strong>2. Define Authorization Methods:</strong></p>
<ul>
<li>In the policy class, define methods for specific actions:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostPolicy</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params">User $user</span>)
    </span>{
        <span class="hljs-comment">// Check if the user has permission to create posts</span>
        <span class="hljs-keyword">return</span> $user-&gt;hasRole(<span class="hljs-string">'author'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">User $user, Post $post</span>)
    </span>{
        <span class="hljs-comment">// Check if the user is the post author or has edit permission</span>
        <span class="hljs-keyword">return</span> $user-&gt;owns($post) || $user-&gt;hasPermission(<span class="hljs-string">'edit posts'</span>);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delete</span>(<span class="hljs-params">User $user, Post $post</span>)
    </span>{
        <span class="hljs-comment">// Check if the user has permission to delete posts</span>
        <span class="hljs-keyword">return</span> $user-&gt;hasPermission(<span class="hljs-string">'delete posts'</span>);
    }
}
</code></pre>
<p><strong>3. Register Policies:</strong></p>
<ul>
<li>Register your policies in the <code>AppServiceProvider</code> to be used by Laravel:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">boot</span>(<span class="hljs-params"></span>)
</span>{
    Gate::define(<span class="hljs-string">'create-post'</span>, <span class="hljs-string">'App\Policies\PostPolicy@create'</span>);
    Gate::define(<span class="hljs-string">'update-post'</span>, <span class="hljs-string">'App\Policies\PostPolicy@update'</span>);
    Gate::define(<span class="hljs-string">'delete-post'</span>, <span class="hljs-string">'App\Policies\PostPolicy@delete'</span>);
}
</code></pre>
<p><strong>4. Use Policies in Controllers:</strong></p>
<ul>
<li>Utilize the defined policies in your controller methods for authorization checks:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">store</span>(<span class="hljs-params">Request $request</span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;authorize(<span class="hljs-string">'create'</span>, Post::class);

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

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update</span>(<span class="hljs-params">Post $post</span>)
</span>{
    <span class="hljs-keyword">$this</span>-&gt;authorize(<span class="hljs-string">'update'</span>, $post);

    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>You can learn more about Laravel policy <a target="_blank" href="https://laravel.com/docs/10.x/authorization#creating-policies">here</a>.</p>
<h3 id="heading-middleware">Middleware:</h3>
<p>Use middleware to enforce authorization checks before specific routes are accessed. This provides a convenient way to ensure that only authorized users can access specific functionalities.<br />Middleware plays a crucial role in Laravel applications by providing a powerful mechanism for intercepting and manipulating requests and responses. Here's an example:</p>
<p><strong>1. Create a Middleware:</strong></p>
<ul>
<li>Generate a middleware class:</li>
</ul>
<pre><code class="lang-bash">php artisan make:middleware AdminMiddleware
</code></pre>
<p>This command creates a middleware class (<code>App\Http\Middleware\AdminMiddleware</code>) that can be used to implement custom logic before and after a request is processed.</p>
<p><strong>2. Define Middleware Logic:</strong></p>
<ul>
<li>In the middleware class, write your logic using the <code>handle</code> method:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdminMiddleware</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params">Request $request, <span class="hljs-built_in">Closure</span> $next</span>)
    </span>{
        $isAdmin = Auth::check() &amp;&amp; $request-&gt;user()-&gt;isAdmin();

        <span class="hljs-keyword">if</span> (!$isAdmin) {
            <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">'/login'</span>);
        }

        <span class="hljs-keyword">return</span> $next($request);
    }
}
</code></pre>
<p>This middleware checks if the user is authenticated before proceeding with the request. If not, it redirects them to the login page.</p>
<p><strong>3. Register Middleware:</strong></p>
<ul>
<li>Register your middleware in the <code>app/Http/Kernel.php</code> file:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-keyword">protected</span> $middleware = [
    <span class="hljs-comment">// ... other middleware ...</span>
    <span class="hljs-string">'admin'</span> =&gt; \App\Http\Middleware\AdminMiddleware::class,
];
</code></pre>
<p>This registers the <code>AdminMiddleware</code> globally for all requests.</p>
<p><strong>4. Apply Middleware to Specific Routes:</strong></p>
<ul>
<li>You can also apply middleware to specific routes using route groups or individual route definitions:</li>
</ul>
<pre><code class="lang-php"><span class="hljs-comment">// Apply middleware to all routes in a group</span>
Route::group([<span class="hljs-string">'middleware'</span> =&gt; [<span class="hljs-string">'auth'</span>, <span class="hljs-string">'admin'</span>]], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Protected routes</span>
});

<span class="hljs-comment">// Apply middleware to a specific route</span>
Route::get(<span class="hljs-string">'/admin'</span>, <span class="hljs-string">'AdminController@index'</span>)-&gt;middleware(<span class="hljs-string">'auth'</span>, <span class="hljs-string">'admin'</span>);
</code></pre>
<p><strong>5. Middleware Parameters:</strong></p>
<ul>
<li>Optionally, you can pass parameters to the middleware through the route definition:</li>
</ul>
<pre><code class="lang-php">Route::get(<span class="hljs-string">'/profile/{user}'</span>, <span class="hljs-string">'UserController@profile'</span>)-&gt;middleware(<span class="hljs-string">'auth:web,admin'</span>);
</code></pre>
<p>This middleware will receive the user ID as a parameter within the <code>handle</code> method. Learn more about Laravel Middleware <a target="_blank" href="https://laravel.com/docs/10.x/middleware">https://laravel.com/docs/10.x/middleware</a></p>
<hr />
<h2 id="heading-advanced-security-practices">Advanced Security Practices:</h2>
<p>Advanced Security Practices constitute a comprehensive and proactive approach aimed at fortifying digital systems against a spectrum of cyber threats, encompassing strategies, tools, and methodologies meticulously designed to safeguard sensitive data, thwart unauthorized access, and bolster overall system resilience. Here are some key points you can follow to secure your application.</p>
<ol>
<li><p><strong>Implement Rate Limiting:</strong> Limit the number of failed login attempts or API requests to prevent brute-force attacks. Laravel provides features like throttling and rate-limiting middleware to mitigate such threats.</p>
</li>
<li><p><strong>Content Security Policy (CSP):</strong> Implement a CSP to define valid sources for scripts, styles, and images. This helps prevent malicious code injection attacks and protects your application from XSS vulnerabilities.</p>
</li>
<li><p><strong>Secure File Uploads:</strong> Implement stringent validation and sanitization procedures for user-uploaded files. This helps prevent file upload vulnerabilities and protects your application from malware injection.</p>
</li>
<li><p><strong>Secure Communication:</strong> Always use HTTPS for secure communication between your application and users, ensuring data is encrypted in transit. This protects against eavesdropping and man-in-the-middle attacks.</p>
</li>
<li><p><strong>Regularly Update and Monitor:</strong> Regularly update Laravel, its dependencies, and packages to benefit from the latest security patches and fixes. Implement logging and monitoring tools to detect suspicious activity in your application and respond promptly to any security incidents.</p>
</li>
</ol>
<p>By implementing these advanced authentication and authorization strategies, you can significantly improve the security posture of your Laravel application. Remember, security is an ongoing process, requiring continuous vigilance and adaptation to evolving threats. By staying informed and proactively implementing security best practices, you can ensure your Laravel application remains a safe and secure haven for your users and their data.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, safeguarding Laravel applications through Advanced Authentication and Authorization Strategies is imperative in today's cybersecurity landscape. By leveraging robust authentication mechanisms, implementing multi-factor authentication, and employing granular authorization controls, developers fortify their applications against diverse threats. These advanced strategies, complemented by encryption, secure session handling, and regular security audits, not only protect sensitive data but also instill user confidence and ensure compliance with stringent security standards.</p>
<p>As digital ecosystems evolve, embracing these advanced practices becomes not just a measure of protection but a commitment to fostering trust, reliability, and resilience in Laravel applications amidst the dynamic and ever-changing threat environment. Through a proactive approach to security, developers establish a solid foundation for the integrity, confidentiality, and availability of their Laravel-powered systems.</p>
<p><strong>Resources</strong></p>
<ul>
<li><p><a target="_blank" href="https://laravel.com/docs/10.x/authorization#creating-policies">Authorization - Laravel 10.x - The PHP Framework For Web Artisans</a></p>
</li>
<li><p><a target="_blank" href="https://laravel.com/docs/10.x/middleware">Laravel middleware</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/antonioribeiro/google2fa-laravel">Google 2FA laravel</a></p>
</li>
<li><p><a target="_blank" href="https://spatie.be/docs/laravel-permission/v6/basic-usage/role-permissions">Spatie laravel permission</a></p>
</li>
<li><p><a target="_blank" href="https://ollieread.com/archive/read/laravel-rbac-role-based-access-control-without-over-engineering/">Role-based access control</a></p>
</li>
<li><p><a target="_blank" href="https://laravel.com/docs/10.x/sanctum">Laravel Sanctum</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[API call in JavaScript & JS frameworks]]></title><description><![CDATA[Interacting with external applications is a necessary thing when we work on front-end applications by API calls. APIs allow different software applications to communicate with each other, enabling developers to access and retrieve data from various s...]]></description><link>https://blog.msar.me/api-call-in-javascript-and-js-frameworks</link><guid isPermaLink="true">https://blog.msar.me/api-call-in-javascript-and-js-frameworks</guid><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Tue, 12 Dec 2023 11:02:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/71CjSSB83Wo/upload/8c854814ada2368f888eceea3269ac6a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Interacting with external applications is a necessary thing when we work on front-end applications by API calls. APIs allow different software applications to communicate with each other, enabling developers to access and retrieve data from various sources. There were many ways to API calls, like fetchAPI, XMLHttpRequest (xhr) &amp; etc.</p>
<p>Here we will discuss fetching API calls and some tools for API calls.</p>
<h2 id="heading-api-call-using-fetch-api">API call using fetch API</h2>
<p>The Fetch API provides an interface for fetching resources (including across the network). It is a more powerful and flexible replacement for <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>.</p>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> provides a JavaScript interface for accessing and manipulating parts of the protocol, such as requests and responses. It also provides a global <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/fetch">fetch()</a> method that provides an easy, logical way to fetch resources asynchronously across the network.</p>
<h3 id="heading-example-of-fetch-api">Example of fetch API</h3>
<p>Here is a simple API call using fetch API</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>

<span class="hljs-comment">// using async-await</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url)
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json()
    <span class="hljs-keyword">return</span> data
}

<span class="hljs-comment">// using then method</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
    fetch(url)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
    .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(data))
    .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(error))
}
</code></pre>
<p>I have shown two types of API calling methods, in this article we will use the first one, to how we catch the error in the first method, Okay, for that we have to wrap the API call with a <code>try-catch</code> block like this.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>

<span class="hljs-comment">// using async-await</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">try</span>{
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url)
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json()
        <span class="hljs-keyword">return</span> data
    }<span class="hljs-keyword">catch</span>(error){
        <span class="hljs-comment">// return the error or throw the error</span>
    }
}
</code></pre>
<p><strong>Let's call another API call with more options.</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">postData</span>(<span class="hljs-params">data = {}</span>) </span>{
  <span class="hljs-comment">// Default options are marked with *</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>, <span class="hljs-comment">// *GET, POST, PUT, DELETE, etc.</span>
    <span class="hljs-attr">mode</span>: <span class="hljs-string">"cors"</span>, <span class="hljs-comment">// no-cors, *cors, same-origin</span>
    <span class="hljs-attr">cache</span>: <span class="hljs-string">"no-cache"</span>, <span class="hljs-comment">// *default, no-cache, reload, force-cache, only-if-cached</span>
    <span class="hljs-attr">credentials</span>: <span class="hljs-string">"same-origin"</span>, <span class="hljs-comment">// include, *same-origin, omit</span>
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      <span class="hljs-string">"Accept"</span>: <span class="hljs-string">"application/json"</span>
    },
    <span class="hljs-attr">redirect</span>: <span class="hljs-string">"follow"</span>, <span class="hljs-comment">// manual, *follow, error</span>
    <span class="hljs-attr">referrerPolicy</span>: <span class="hljs-string">"no-referrer"</span>, <span class="hljs-comment">// no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url</span>
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data), <span class="hljs-comment">// body data type must match "Content-Type" header</span>
  });
  <span class="hljs-keyword">return</span> response.json() <span class="hljs-comment">// parses JSON response into native JavaScript objects</span>
}

<span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> postData({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Update the API call'</span> })
<span class="hljs-built_in">console</span>.log(data) <span class="hljs-comment">// JSON data parsed by `response.json()` call</span>
<span class="hljs-comment">// {"title": "Update the API call", "id": 201}</span>
</code></pre>
<p>You can pass your header by the example above or you can also pass a header instance</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> myHeaders = <span class="hljs-keyword">new</span> Headers({
  <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"text/plain"</span>,
  <span class="hljs-string">"Accept"</span>: <span class="hljs-string">"application/json"</span>
  <span class="hljs-string">"X-Custom-Header"</span>: <span class="hljs-string">"ProcessThisImmediately"</span>,
})
</code></pre>
<h3 id="heading-canceling-a-request">Canceling a request</h3>
<p>Sometimes we need to cancel an API call after calling the API, To abort incomplete <code>fetch()</code> operations, fetch-API can do it easily with the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/AbortController"><code>AbortController</code></a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal"><code>AbortSignal</code></a> interfaces.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController()
<span class="hljs-keyword">const</span> signal = controller.signal
<span class="hljs-keyword">const</span> url = <span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>

<span class="hljs-keyword">const</span> fetchBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#fetch-todos"</span>)
<span class="hljs-keyword">const</span> abortBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#abort"</span>)

fetchBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, { signal })
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Fetch complete"</span>, response)
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Fetch error: <span class="hljs-subst">${error.message}</span>`</span>)
  }
});

abortBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  controller.abort()
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Fetch aborted"</span>)
});
</code></pre>
<p>In the current world, all the API responses are within a few milliseconds so you can test this API call by modifying your network interceptor to slow 3G connection.</p>
<h3 id="heading-upload-file-using-fetch-api">Upload file using fetch API</h3>
<p>In modern web applications, there must be file upload requirements, so how we can do it with fetch API, for the file upload methodology we have to add the data as <code>FormData</code> is an example 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">upload</span>(<span class="hljs-params">formData</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://example.com/profile/avatar"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"PUT"</span>,
      <span class="hljs-attr">body</span>: formData,
    });
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Success:"</span>, result);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error:"</span>, error);
  }
}

<span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> FormData()
<span class="hljs-keyword">const</span> fileField = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'input[type="file"]'</span>)

formData.append(<span class="hljs-string">"username"</span>, <span class="hljs-string">"msar"</span>)
formData.append(<span class="hljs-string">"avatar"</span>, fileField.files[<span class="hljs-number">0</span>])

upload(formData)
</code></pre>
<p>Enough for fetch API if you want to learn more about the fetch API you can browse <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">MDN</a> documentation or JavaScript.info <a target="_blank" href="https://javascript.info/fetch-api">docs</a>.</p>
<hr />
<h2 id="heading-alternate-to-fetch-api-axios">Alternate to fetch API - Axios</h2>
<p>There were many tools for API calls, <a target="_blank" href="https://axios-http.com/">Axios</a> is a great alternative tool for API calls in JS, and Axios is a simple promise-based HTTP client for the browser and node.js. Axios provides a simple-to-use library in a small package with a very extensible interface.</p>
<p>Loading the Axios library</p>
<p>To load the Axios library you can add this line to your HTML page <code>&lt;script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"&gt;&lt;/script&gt;</code> or you can add the package via npm/yarn <code>npm install axios</code> or <code>yarn add axios</code> in this article we use as yarn package.</p>
<p>Basic example to send an API call using Axios.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-comment">// Make a request for a user with a given ID</span>
axios.get(<span class="hljs-string">'/user?ID=12345'</span>)
  .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
    <span class="hljs-comment">// handle success</span>
    <span class="hljs-built_in">console</span>.log(response)
  })
  .catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error</span>) </span>{
    <span class="hljs-comment">// handle error</span>
    <span class="hljs-built_in">console</span>.log(error)
  })
  .finally(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// always executed</span>
  })

<span class="hljs-comment">// Want to use async/await? Add the `async` keyword to your outer function/method.</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUser</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'/user?ID=12345'</span>)
    <span class="hljs-built_in">console</span>.log(response)
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error)
  }
}
</code></pre>
<p>In this example, the API request will send an API call to this URL, <code>/user</code></p>
<h3 id="heading-digging-deeper-with-axios">Digging deeper with Axios</h3>
<p>We can call the APIs via Axios in many ways, we can pass a full config to the Axios instance</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> base_url <span class="hljs-string">"https://jsonplaceholder.typicode.com"</span>
<span class="hljs-comment">// Send a POST request</span>
axios({
  <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
  <span class="hljs-attr">url</span>: <span class="hljs-string">`<span class="hljs-subst">${base_url}</span>/users`</span>,
  <span class="hljs-attr">data</span>: {
    <span class="hljs-attr">firstName</span>: <span class="hljs-string">'Fred'</span>,
    <span class="hljs-attr">lastName</span>: <span class="hljs-string">'Flintstone'</span>
  }
})

<span class="hljs-comment">// Send a GET request (default method)</span>
<span class="hljs-comment">// GET request without options or anything.</span>
axios(<span class="hljs-string">`<span class="hljs-subst">${base_url}</span>/users`</span>)

<span class="hljs-comment">// the structure of axios</span>
axios(url[, config])
</code></pre>
<p>here is a list of available methods Axios provides.</p>
<h4 id="heading-request-method-aliases">Request method aliases</h4>
<p>For convenience, aliases have been provided for all supported request methods.</p>
<h5 id="heading-axiosrequestconfig"><code>axios.request(config)</code></h5>
<h5 id="heading-axiosgeturl-config"><code>axios.get(url[, config])</code></h5>
<h5 id="heading-axiosdeleteurl-config"><code>axios.delete(url[, config])</code></h5>
<h5 id="heading-axiosheadurl-config"><code>axios.head(url[, config])</code></h5>
<h5 id="heading-axiosoptionsurl-config"><code>axios.options(url[, config])</code></h5>
<h5 id="heading-axiosposturl-data-config"><code>axios.post(url[, data[, config]])</code></h5>
<h5 id="heading-axiosputurl-data-config"><code>axios.put(url[, data[, config]])</code></h5>
<h5 id="heading-axiospatchurl-data-config"><code>axios.patch(url[, data[, config]])</code></h5>
<h5 id="heading-axiospostformurl-data-config"><code>axios.postForm(url[, data[, config]])</code></h5>
<h5 id="heading-axiosputformurl-data-config"><code>axios.putForm(url[, data[, config]])</code></h5>
<h5 id="heading-axiospatchformurl-data-config"><code>axios.patchForm(url[, data[, config]])</code></h5>
<h3 id="heading-customizing-axios">Customizing Axios</h3>
<p>We can create multiple instances for the Axios and use it as our necessity.<br />we can create an instance, and use it in our next API calls.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> instance = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">'https://jsonplaceholder.typicode.com'</span>,
  <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Accept'</span>: <span class="hljs-string">'application/json'</span>
  },
  <span class="hljs-attr">transformRequest</span>: [<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data, headers</span>) </span>{
    <span class="hljs-comment">// Do whatever you want to transform the data</span>
    <span class="hljs-keyword">return</span> data;
  }],
  <span class="hljs-comment">// `transformResponse` allows changes to </span>
  <span class="hljs-comment">// the response data to be made before</span>
  <span class="hljs-comment">// it is passed to then/catch</span>
  <span class="hljs-attr">transformResponse</span>: [<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
    <span class="hljs-comment">// Do whatever you want to transform the data</span>
    <span class="hljs-keyword">return</span> data;
  }],
});

<span class="hljs-comment">// API call</span>
instance.get(<span class="hljs-string">'/todos'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response.data)
    })

<span class="hljs-comment">// response will be</span>
<span class="hljs-comment">// [</span>
<span class="hljs-comment">//   {</span>
<span class="hljs-comment">//     "userId": 1,</span>
<span class="hljs-comment">//     "id": 1,</span>
<span class="hljs-comment">//     "title": "delectus aut autem",</span>
<span class="hljs-comment">//     "completed": false</span>
<span class="hljs-comment">//   },</span>
<span class="hljs-comment">//   {</span>
<span class="hljs-comment">//     "userId": 1,</span>
<span class="hljs-comment">//     "id": 2,</span>
<span class="hljs-comment">//     "title": "quis ut nam facilis et officia qui",</span>
<span class="hljs-comment">//     "completed": false</span>
<span class="hljs-comment">//   },</span>
<span class="hljs-comment">// ......</span>
</code></pre>
<p>Now we can just call the rest of the path, we don't need to pass the whole URLs,</p>
<p><code>transformRequest</code> will transform our request config or data before calling the API, <code>transformResponse</code> will transform the response after successfully calling the API.<br />more config can be found <a target="_blank" href="https://axios-http.com/docs/req_config">here</a>. We can create a global instance, so every time we use the <code>axios</code> we do not need to pass the config on each request, we can do that by,</p>
<pre><code class="lang-javascript">axios.defaults.baseURL = <span class="hljs-string">'https://jsonplaceholder.typicode.com'</span>;
axios.defaults.headers.common[<span class="hljs-string">'Authorization'</span>] = AUTH_TOKEN;
axios.defaults.headers.post[<span class="hljs-string">'Content-Type'</span>] = <span class="hljs-string">'application/json'</span>;
</code></pre>
<p>So in this process, we can use the axios method directly as below.</p>
<pre><code class="lang-javascript">axios.get(<span class="hljs-string">'/todos'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(response.data)
    })
</code></pre>
<p>In Axios, we can use interceptors, for the request and response.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Add a request interceptor</span>
axios.interceptors.request.use(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">config</span>) </span>{
    <span class="hljs-comment">// Do something before request is sent</span>
    <span class="hljs-keyword">return</span> config;
  }, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error</span>) </span>{
    <span class="hljs-comment">// Do something with request error</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error);
  });

<span class="hljs-comment">// Add a response interceptor</span>
axios.interceptors.response.use(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
    <span class="hljs-comment">// Any status code that lie within the range of 2xx cause this function to trigger</span>
    <span class="hljs-comment">// Do something with response data</span>
    <span class="hljs-keyword">return</span> response;
  }, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error</span>) </span>{
    <span class="hljs-comment">// Any status codes that falls outside the range of 2xx cause this function to trigger</span>
    <span class="hljs-comment">// Do something with response error</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error);
  });
</code></pre>
<p>If you see we log the <code>response.data</code> - not the response, so what contains the response property, the response property contains the data as below.</p>
<pre><code class="lang-javascript">{
  <span class="hljs-comment">// `data` is the response that was provided by the server</span>
  <span class="hljs-attr">data</span>: {},

  <span class="hljs-comment">// `status` is the HTTP status code from the server response</span>
  <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,

  <span class="hljs-comment">// `statusText` is the HTTP status message from the server response</span>
  <span class="hljs-comment">// As of HTTP/2 status text is blank or unsupported.</span>
  <span class="hljs-comment">// (HTTP/2 RFC: https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.4)</span>
  <span class="hljs-attr">statusText</span>: <span class="hljs-string">'OK'</span>,

  <span class="hljs-comment">// `headers` the HTTP headers that the server responded with</span>
  <span class="hljs-comment">// All header names are lower cased and can be accessed using the bracket notation.</span>
  <span class="hljs-comment">// Example: `response.headers['content-type']`</span>
  <span class="hljs-attr">headers</span>: {},

  <span class="hljs-comment">// `config` is the config that was provided to `axios` for the request</span>
  <span class="hljs-attr">config</span>: {},

  <span class="hljs-comment">// `request` is the request that generated this response</span>
  <span class="hljs-comment">// It is the last ClientRequest instance in node.js (in redirects)</span>
  <span class="hljs-comment">// and an XMLHttpRequest instance in the browser</span>
  <span class="hljs-attr">request</span>: {}
}
</code></pre>
<p>Axios provides a handy configuration for request cancelation as before we saw the fetch API abort controller.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

<span class="hljs-keyword">const</span> CancelToken = axios.CancelToken;
<span class="hljs-keyword">const</span> source = CancelToken.source();

axios.get(<span class="hljs-string">'/user/12345'</span>, {
  <span class="hljs-attr">cancelToken</span>: source.token,
  <span class="hljs-attr">signal</span>: controller.signal
}).catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">thrown</span>) </span>{
  <span class="hljs-keyword">if</span> (axios.isCancel(thrown)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Request canceled'</span>, thrown.message);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// handle error</span>
  }
});

axios.post(<span class="hljs-string">'/user/12345'</span>, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'new name'</span>
}, {
  <span class="hljs-attr">cancelToken</span>: source.token
})

<span class="hljs-comment">// cancel the request (the message parameter is optional)</span>
source.cancel(<span class="hljs-string">'Operation canceled by the user.'</span>);
<span class="hljs-comment">// OR</span>
controller.abort(); <span class="hljs-comment">// the message parameter is not supported</span>
</code></pre>
<p>More details about cancel tokens can be found <a target="_blank" href="https://axios-http.com/docs/cancellation">here</a>.</p>
<p>Okay, let's deep dive into the API calling process, The above two processes can be used anywhere in a javascript application. But what if we use those in a React application or any front-end application? Okay now let's talk about it.</p>
<h2 id="heading-api-call-in-a-react-application">API call in a react application</h2>
<p>There are many ways to call the API in a React application.</p>
<p>We can use <code>useEffect</code> hook and <code>useState</code> to store the data an example below.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);

useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts?_limit=10'</span>)
      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
      .then(<span class="hljs-function"><span class="hljs-params">json</span> =&gt;</span> setData(json))
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
}, []);
</code></pre>
<p>In this process, the problem is if we have to call the data again in another component we can't do that, yes if we separate the logic to a custom hook it can be possible.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> usePosts = <span class="hljs-function">(<span class="hljs-params">{ per_page = <span class="hljs-number">10</span>, page = <span class="hljs-number">1</span> }</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);

    useEffect(<span class="hljs-function">() =&gt;</span> {
        fetch(
            <span class="hljs-string">`https://jsonplaceholder.typicode.com/posts?_limit=<span class="hljs-subst">${per_page}</span>&amp;_page=<span class="hljs-subst">${page}</span>`</span>
        )
            .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
            .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> setData(json))
            .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
    }, []);

    <span class="hljs-keyword">return</span> data;
};
</code></pre>
<p>But every time we call the hook the same API will be called as our data is the same, we can prevent it by saving the first API-called data to a global store or something else. In this process we can't get the metadata like the loading state, fetching state or maybe the re-fetch functionality, then we have to create all the things from scratch.<br />But there were many smooth and good ways to do that, like.</p>
<ul>
<li><p>useSWR hook by Vercel</p>
</li>
<li><p>ReactQuery by tanstack</p>
</li>
</ul>
<p>Okay, let's call our API with that.</p>
<h3 id="heading-vercel-useswr-hook">Vercel useSWR hook</h3>
<p>SWR is a handy and lightweight tool to manage these API calls and data fetching.</p>
<p>SWR features as their <a target="_blank" href="https://swr.vercel.app/">website</a></p>
<ul>
<li><h4 id="heading-lightweight"><strong>Lightweight</strong></h4>
</li>
<li><h4 id="heading-realtime"><strong>Realtime</strong></h4>
</li>
<li><h4 id="heading-suspense"><strong>Suspense</strong></h4>
</li>
<li><h4 id="heading-pagination"><strong>Pagination</strong></h4>
</li>
<li><h4 id="heading-backend-agnostic"><strong>Backend Agnostic</strong></h4>
</li>
<li><h4 id="heading-ssr-ssg-ready"><strong>SSR / SSG Ready</strong></h4>
</li>
<li><h4 id="heading-typescript-ready"><strong>TypeScript Ready</strong></h4>
</li>
<li><h4 id="heading-remote-local"><strong>Remote + Local</strong></h4>
</li>
</ul>
<p>To use SWR in our application first, we have to install it.<br /><code>yarn add swr</code> after successfully installed we can use it like this.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSWR <span class="hljs-keyword">from</span> <span class="hljs-string">'swr'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Profile</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, error, isLoading } = useSWR(<span class="hljs-string">'/api/user'</span>, fetcher)

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>failed to load<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>loading...<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>&gt;</span>hello {data.name}!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>Here <code>fetcher</code> could be the Axios instance or the fetch instance.</p>
<p>Let's make a hook, so our SWR does not need to pass the key every time.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSWR <span class="hljs-keyword">from</span> <span class="hljs-string">"swr"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useUser</span>(<span class="hljs-params">userId</span>) </span>{
    <span class="hljs-keyword">const</span> { data, error, isLoading } = useSWR(
      <span class="hljs-string">"/api/user"</span>, <span class="hljs-comment">// key</span>
      <span class="hljs-function">() =&gt;</span> fetch(<span class="hljs-string">`/api/user/<span class="hljs-subst">${userId}</span>`</span>).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json()) <span class="hljs-comment">//fetcher</span>
    );

    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">user</span>: data,
      isLoading,
      error,
    };
}
</code></pre>
<p>So what is it?</p>
<p>Okay, here in the <code>useSWR</code> hooks' first attribute is the unique key for the request, and the second one is the fetcher, there are other attribute options which is optional, so the SWR looks like this.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { data, error, isLoading, isValidating, mutate } = useSWR(key, fetcher, options)
</code></pre>
<p>By default, <code>key</code> will be passed to <code>fetcher</code> as the argument. So the following 3 expressions are equivalent:</p>
<pre><code class="lang-javascript">useSWR(<span class="hljs-string">'/api/user'</span>, <span class="hljs-function">() =&gt;</span> fetcher(<span class="hljs-string">'/api/user'</span>))
useSWR(<span class="hljs-string">'/api/user'</span>, <span class="hljs-function"><span class="hljs-params">url</span> =&gt;</span> fetcher(url))
useSWR(<span class="hljs-string">'/api/user'</span>, fetcher)
</code></pre>
<p>In options, we can pass a custom config for the request.</p>
<p>Options receive these properties.</p>
<ul>
<li><p><code>suspense = false</code>: enable React Suspense mode</p>
</li>
<li><p><code>fetcher(args)</code>: the fetcher function</p>
</li>
<li><p><code>revalidateIfStale = true</code>: automatically revalidate even if there is stale data</p>
</li>
<li><p><code>revalidateOnMount</code>: enable or disable automatic revalidation when the component is mounted</p>
</li>
<li><p><code>revalidateOnFocus = true</code>: automatically revalidate when the window gets focused</p>
</li>
<li><p><code>revalidateOnReconnect = true</code>: automatically revalidate when the browser regains a network connection (via <a target="_blank" href="https://swr.vercel.app/docs/suspense"><code>navigator.onLine</code></a>) <a target="_blank" href="https://swr.vercel.app/docs/revalidation">(details)</a></p>
</li>
<li><p><code>refreshInterval</code> <a target="_blank" href="https://swr.vercel.app/docs/revalidation">(details)</a>:</p>
<ul>
<li><p>Disabled by default: <code>refreshInterval = 0</code></p>
</li>
<li><p>If set to a number, the polling interval in milliseconds</p>
</li>
<li><p>If set to a function, the function will receive the latest data and should return the interval in milliseconds</p>
</li>
</ul>
</li>
<li><p><code>refreshWhenHidden = false</code>: polling when the window is invisible (if <code>refreshInterval</code> is enabled)</p>
</li>
<li><p><code>refreshWhenOffline = false</code>: polling when the browser is offline (determined by <a target="_blank" href="https://swr.vercel.app/docs/suspense"><code>navigator.onLine</code></a>)</p>
</li>
<li><p><code>shouldRetryOnError = true</code>: retry when fetcher has an error</p>
</li>
<li><p><code>dedupingInterval = 2000</code>: dedupe requests with the same key in this time span in milliseconds</p>
</li>
<li><p><code>focusThrottleInterval = 5000</code>: only revalidate once during a time span in milliseconds</p>
</li>
<li><p><code>loadingTimeout = 3000</code>: timeout to trigger the onLoadingSlow event in milliseconds</p>
</li>
<li><p><code>errorRetryInterval = 5000</code>: error retry interval in milliseconds</p>
</li>
<li><p><code>errorRetryCount</code>: max error retry count</p>
</li>
<li><p><code>fallback</code>: a key-value object of multiple fallback data <a target="_blank" href="https://swr.vercel.app/docs/with-nextjs">(example)</a></p>
</li>
<li><p><code>fallbackData</code>: initial data to be returned (note: This is per-hook)</p>
</li>
<li><p><code>keepPreviousData = false</code>: return the previous key's data until the new data has been loaded <a target="_blank" href="https://swr.vercel.app/docs/advanced/understanding#return-previous-data-for-better-ux">(details)</a></p>
</li>
<li><p><code>onLoadingSlow(key, config)</code>: callback function when a request takes too long to load (see <code>loadingTimeout</code>)</p>
</li>
<li><p><code>onSuccess(data, key, config)</code>: callback function when a request finishes successfully</p>
</li>
<li><p><code>onError(err, key, config)</code>: callback function when a request returns an error</p>
</li>
<li><p><code>onErrorRetry(err, key, config, revalidate, revalidateOps)</code>: handler for error retry</p>
</li>
<li><p><code>onDiscarded(key)</code>: callback function when a request is ignored due to race conditions</p>
</li>
<li><p><code>compare(a, b)</code>: comparison function used to detect when returned data has changed, to avoid spurious rerenders. By default, stable-hash is used.</p>
</li>
<li><p><code>isPaused()</code>: function to detect whether pause revalidations, will ignore fetched data and errors when it returns <code>true</code>. Returns <code>false</code> by default.</p>
</li>
<li><p><code>use</code>: array of middleware functions</p>
</li>
</ul>
<p>More details can be found <a target="_blank" href="https://swr.vercel.app/docs/api">here</a>.</p>
<p>Instead of passing the configuration, we can use a global configuration for the SWR.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSWR, { SWRConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'swr'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: events } = useSWR(<span class="hljs-string">'/api/events'</span>)
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: projects } = useSWR(<span class="hljs-string">'/api/projects'</span>)
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: user } = useSWR(<span class="hljs-string">'/api/user'</span>, { <span class="hljs-attr">refreshInterval</span>: <span class="hljs-number">0</span> }) <span class="hljs-comment">// override</span>

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

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SWRConfig</span> 
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">refreshInterval:</span> <span class="hljs-attr">3000</span>,
        <span class="hljs-attr">fetcher:</span> (<span class="hljs-attr">resource</span>, <span class="hljs-attr">init</span>) =&gt;</span> fetch(resource, init).then(res =&gt; res.json())
      }}
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Dashboard</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">SWRConfig</span>&gt;</span></span>
  )
}
</code></pre>
<p><strong>In return, the hooks give us</strong></p>
<ul>
<li><p><code>data</code>: data for the given key resolved by the <code>fetcher</code> (or undefined if not loaded)</p>
</li>
<li><p><code>error</code>: error thrown by <code>fetcher</code> (or undefined)</p>
</li>
<li><p><code>isLoading</code>: if there's an ongoing request and no "loaded data". Fallback data and previous data are not considered "loaded data"</p>
</li>
<li><p><code>isValidating</code>: if there's a request or revalidation loading</p>
</li>
<li><p><code>mutate(data?, options?)</code>: function to mutate the cached data</p>
</li>
</ul>
<p><strong>Axios example</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>

<span class="hljs-keyword">const</span> fetcher = <span class="hljs-function"><span class="hljs-params">url</span> =&gt;</span> axios.get(url).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.data)

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, error } = useSWR(<span class="hljs-string">'/api/data'</span>, fetcher)
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>For data mutation, SWR provides a <code>mutate</code> method to mutate the cached data</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSWR <span class="hljs-keyword">from</span> <span class="hljs-string">'swr'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Profile</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, mutate } = useSWR(<span class="hljs-string">'/api/user'</span>, fetcher)

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> newName = data.name.toUpperCase()
        <span class="hljs-comment">// send a request to the API to update the data</span>
        <span class="hljs-keyword">await</span> requestUpdateUsername(newName)
        <span class="hljs-comment">// update the local data immediately and revalidate (refetch)</span>
        <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> key is not required when using useSWR's mutate as it's pre-bound</span>
        mutate({ ...data, <span class="hljs-attr">name</span>: newName })
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is {data.name}.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Uppercase my name!<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>
  )
}
</code></pre>
<p>More about mutation can be found <a target="_blank" href="https://swr.vercel.app/docs/mutation">here</a>.</p>
<h4 id="heading-conditional"><strong>Conditional</strong></h4>
<p>Use <code>null</code> or pass a function as <code>key</code> to conditionally fetch data. If the function throws or returns a false value, SWR will not start the request.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// conditionally fetch</span>
<span class="hljs-keyword">const</span> { data } = useSWR(shouldFetch ? <span class="hljs-string">'/api/data'</span> : <span class="hljs-literal">null</span>, fetcher)

<span class="hljs-comment">// ...or return a falsy value</span>
<span class="hljs-keyword">const</span> { data } = useSWR(<span class="hljs-function">() =&gt;</span> shouldFetch ? <span class="hljs-string">'/api/data'</span> : <span class="hljs-literal">null</span>, fetcher)

<span class="hljs-comment">// ...or throw an error when user.id is not defined</span>
<span class="hljs-keyword">const</span> { data } = useSWR(<span class="hljs-function">() =&gt;</span> <span class="hljs-string">'/api/data?uid='</span> + user.id, fetcher)
</code></pre>
<h4 id="heading-prefetch">Prefetch</h4>
<p>SWR provides the <code>preload</code> API to prefetch the resources programmatically and store the results in the cache. <code>preload</code> accepts <code>key</code> and <code>fetcher</code> as the arguments.</p>
<p>You can call <code>preload</code> even outside of React.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> useSWR, { preload } <span class="hljs-keyword">from</span> <span class="hljs-string">'swr'</span>

<span class="hljs-keyword">const</span> fetcher = <span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> fetch(url).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())

<span class="hljs-comment">// Preload the resource before rendering the User component below,</span>
<span class="hljs-comment">// this prevents potential waterfalls in your application.</span>
<span class="hljs-comment">// You can also start preloading when hovering the button or link, too.</span>
preload(<span class="hljs-string">'/api/user'</span>, fetcher)

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data } = useSWR(<span class="hljs-string">'/api/user'</span>, fetcher)
  ...
}

<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"></span>) </span>{
  <span class="hljs-keyword">const</span> [show, setShow] = useState(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setShow(true)}&gt;Show User<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {show ? <span class="hljs-tag">&lt;<span class="hljs-name">User</span> /&gt;</span> : null}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>There were beautiful docs for <a target="_blank" href="https://swr.vercel.app/">SWR</a>, you can look at them for more details.</p>
<p>Okay, SWR is the simplest way to handle the API request, but maybe you need something more than you must use the react-query to handle your API calls.</p>
<hr />
<h3 id="heading-react-query">React Query</h3>
<p><strong>Powerful asynchronous state management for TS/JS, React, Solid, Vue and Svelte</strong></p>
<p>Toss out that granular state management, manual re-fetching and endless bowls of async-spaghetti code. TanStack Query gives you declarative, always-up-to-date auto-managed queries and mutations that <strong>directly improve both your developer and user experiences</strong>.</p>
<p>React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes <strong>fetching, caching, synchronizing and updating server state</strong> in your React applications a breeze.</p>
<p><strong>#Enough talk, show me some code already!</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { QueryClient, QueryClientProvider, useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-query'</span>

<span class="hljs-keyword">const</span> queryClient = <span class="hljs-keyword">new</span> QueryClient()

<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"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">QueryClientProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{queryClient}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Example</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">QueryClientProvider</span>&gt;</span></span>
  )
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Example</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { isLoading, error, data } = useQuery(<span class="hljs-string">'repoData'</span>, <span class="hljs-function">() =&gt;</span>
    fetch(<span class="hljs-string">'https://api.github.com/repos/tannerlinsley/react-query'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span>
      res.json()
    )
  )

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="hljs-string">'Loading...'</span>

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="hljs-string">'An error has occurred: '</span> + error.message

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{data.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data.description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>👀 {data.subscribers_count}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>{' '}
      <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>✨ {data.stargazers_count}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>{' '}
      <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>🍴 {data.forks_count}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>So let's install the react-query</p>
<pre><code class="lang-bash">npm i react-query
<span class="hljs-comment"># or</span>
yarn add react-query
</code></pre>
<h3 id="heading-a-quick-start">A quick start</h3>
<p>Here is a quick start example.<br />This example very briefly illustrates the 3 core concepts of React Query:</p>
<ul>
<li><p><a target="_blank" href="https://tanstack.com/query/v3/docs/react/guides/queries"><strong>Queries</strong></a></p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/v3/docs/react/guides/mutations"><strong>Mutations</strong></a></p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/v3/docs/react/guides/query-invalidation"><strong>Query Invalidation</strong></a></p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'react-query'</span>
<span class="hljs-keyword">import</span> { getTodos, postTodo } <span class="hljs-keyword">from</span> <span class="hljs-string">'../my-api'</span>

<span class="hljs-comment">// Create a client</span>
<span class="hljs-keyword">const</span> queryClient = <span class="hljs-keyword">new</span> QueryClient()

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// Provide the client to your App</span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">QueryClientProvider</span> <span class="hljs-attr">client</span>=<span class="hljs-string">{queryClient}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Todos</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">QueryClientProvider</span>&gt;</span></span>
  )
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todos</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Access the client</span>
  <span class="hljs-keyword">const</span> queryClient = useQueryClient()

  <span class="hljs-comment">// Queries</span>
  <span class="hljs-keyword">const</span> query = useQuery(<span class="hljs-string">'todos'</span>, getTodos)

  <span class="hljs-comment">// Mutations</span>
  <span class="hljs-keyword">const</span> mutation = useMutation(postTodo, {
    <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// Invalidate and refetch</span>
      queryClient.invalidateQueries(<span class="hljs-string">'todos'</span>)
    },
  })

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

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
          mutation.mutate({
            id: Date.now(),
            title: 'Do Laundry',
          })
        }}
      &gt;
        Add Todo
      <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>
  )
}

render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>))
</code></pre>
<p>These three concepts make up most of the core functionality of React Query. The next sections of the documentation will go over each of these core concepts in great detail.</p>
<p>Let's describe this.</p>
<p>At first, we have to create a <code>QueryClient</code> instance and provide it to the <code>QueryClientProvider</code> and the <code>QueryClientProvider</code> should be on top of the application so we can use the client inside the components.</p>
<p>So in the <code>Todos</code> component you see there were some hooks from the react-query we used, <code>useQueryClient</code> gives us the instance of the react-query client initiated by the provider, <code>useQuery</code> is the actual query hook that we will use each time and the <code>useMutation</code> hook is to revalidate the data after a successful update or delete operation.</p>
<h3 id="heading-more-about-usequery-hook">More about useQuery hook</h3>
<p>A query is a declarative dependency on an asynchronous source of data that is tied to a <strong>unique key</strong>. A query can be used with any Promise-based method (including GET and POST methods) to fetch data from a server.</p>
<p>To subscribe to a query in your components or custom hooks, call the <code>useQuery</code> hook with at least:</p>
<ul>
<li><p>A <strong>unique key for the query</strong></p>
</li>
<li><p>A function that returns a promise that:</p>
<ul>
<li><p>Resolves the data, or</p>
</li>
<li><p>Throws an error</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> result = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)
</code></pre>
<p>The <code>result</code> object contains a few very important states you'll need to be aware of to be productive. A query can only be in one of the following states at any given moment:</p>
<ul>
<li><p><code>isLoading</code> or <code>status === 'loading'</code> - The query has no data and is currently fetching</p>
</li>
<li><p><code>isError</code> or <code>status === 'error'</code> - The query encountered an error</p>
</li>
<li><p><code>isSuccess</code> or <code>status === 'success'</code> - The query was successful and data is available</p>
</li>
<li><p><code>isIdle</code> or <code>status === 'idle'</code> - The query is currently disabled (you'll learn more about this in a bit)</p>
</li>
</ul>
<p>Beyond those primary states, more information is available depending on the state of the query:</p>
<ul>
<li><p><code>error</code> - If the query is in an <code>isError</code> state, the error is available via the <code>error</code> property.</p>
</li>
<li><p><code>data</code> - If the query is in a <code>success</code> state, the data is available via the <code>data</code> property.</p>
</li>
<li><p><code>isFetching</code> - In any state, if the query is fetching at any time (including background refetching) <code>isFetching</code> will be <code>true</code>.</p>
</li>
</ul>
<p>For <strong>most</strong> queries, it's usually sufficient to check for the <code>isLoading</code> state, then the <code>isError</code> state, then finally, assume that the data is available and render the successful state:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todos</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { isLoading, isError, data, error } = useQuery(<span class="hljs-string">'todos'</span>, fetchTodoList)

  <span class="hljs-keyword">if</span> (isLoading) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
  }

  <span class="hljs-keyword">if</span> (isError) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
  }

  <span class="hljs-comment">// We can assume by this point that `isSuccess === true`</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {data.map(todo =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>{todo.title}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
  )
}
</code></pre>
<h4 id="heading-the-query-key"><strong>The Query Key</strong></h4>
<p>The query key can be a string, array, or object.<br />If something is dependable you should include it as a query key.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todos</span>(<span class="hljs-params">{ todoId }</span>) </span>{
  <span class="hljs-keyword">const</span> result = useQuery([<span class="hljs-string">'todos'</span>, todoId], <span class="hljs-function">() =&gt;</span> fetchTodoById(todoId))
}

<span class="hljs-comment">// Example of key</span>
<span class="hljs-comment">// A list of todos</span>
useQuery(<span class="hljs-string">'todos'</span>, ...) <span class="hljs-comment">// queryKey === ['todos']</span>

<span class="hljs-comment">// Something else, whatever!</span>
useQuery(<span class="hljs-string">'somethingSpecial'</span>, ...) <span class="hljs-comment">// queryKey === ['somethingSpecial']</span>

<span class="hljs-comment">// An individual todo</span>
useQuery([<span class="hljs-string">'todo'</span>, <span class="hljs-number">5</span>], ...)
<span class="hljs-comment">// queryKey === ['todo', 5]</span>

<span class="hljs-comment">// An individual todo in a "preview" format</span>
useQuery([<span class="hljs-string">'todo'</span>, <span class="hljs-number">5</span>, { <span class="hljs-attr">preview</span>: <span class="hljs-literal">true</span> }], ...)
<span class="hljs-comment">// queryKey === ['todo', 5, { preview: true }]</span>

<span class="hljs-comment">// A list of todos that are "done"</span>
useQuery([<span class="hljs-string">'todos'</span>, { <span class="hljs-attr">type</span>: <span class="hljs-string">'done'</span> }], ...)
<span class="hljs-comment">// queryKey === ['todos', { type: 'done' }]</span>
</code></pre>
<h4 id="heading-query-functions"><strong>Query Functions</strong></h4>
<p>A query function can be literally any function that <strong>returns a promise</strong>. The promise that is returned should either <strong>resolve the data</strong> or <strong>throw an error</strong>.</p>
<pre><code class="lang-javascript">useQuery([<span class="hljs-string">'todos'</span>], fetchAllTodos)
useQuery([<span class="hljs-string">'todos'</span>, todoId], <span class="hljs-function">() =&gt;</span> fetchTodoById(todoId))
useQuery([<span class="hljs-string">'todos'</span>, todoId], <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchTodoById(todoId)
  <span class="hljs-keyword">return</span> data
})
useQuery([<span class="hljs-string">'todos'</span>, todoId], <span class="hljs-function">(<span class="hljs-params">{ queryKey }</span>) =&gt;</span> fetchTodoById(queryKey[<span class="hljs-number">1</span>]))
<span class="hljs-comment">// throughing an error</span>
useQuery([<span class="hljs-string">'todos'</span>, todoId], <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/todos/'</span> + todoId)
  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Network response was not ok'</span>)
  }
  <span class="hljs-keyword">return</span> response.json()
})
</code></pre>
<p><strong>Using a Query Object instead of parameters</strong></p>
<p>Anywhere the <code>[queryKey, queryFn, config]</code> signature is supported throughout React Query's API, you can also use an object to express the same configuration:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-query'</span>

useQuery({
  <span class="hljs-attr">queryKey</span>: [<span class="hljs-string">'todo'</span>, <span class="hljs-number">7</span>],
  <span class="hljs-attr">queryFn</span>: fetchTodo,
  ...config,
})
</code></pre>
<p><code>react-query</code> is a huge feature list that is used as needed, as it is a large library to handle the API calls I think this basic is enough for now, to more details and dive I will share another individual article for this, IA.</p>
<p>for now, you can look at the documentation of <a target="_blank" href="https://tanstack.com/query/v3/">react-query</a> and the <a target="_blank" href="https://tkdodo.eu/blog/tags/react-query">tkdodo</a> blogs.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, JavaScript offers a plethora of options for making API calls, each with its own advantages and specific use cases. The Fetch API provides a built-in method for fetching resources across the web, offering a straightforward and modern interface. Axios, on the other hand, simplifies the process of making HTTP requests with additional features like interceptors and support for older browsers. For React applications, libraries like useSWR and react-query enhance data fetching by providing caching, revalidation, and a more streamlined approach to handling asynchronous data.</p>
<p>Ultimately, the choice of which method or library to use depends on the project requirements, developer preferences, and the specific functionalities needed. Understanding the nuances and strengths of each approach empowers developers to efficiently retrieve and manage data, ensuring a smoother and more responsive user experience in their web applications.</p>
<h4 id="heading-resources">Resources</h4>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API</a></p>
</li>
<li><p><a target="_blank" href="https://axios-http.com/">https://axios-http.com/</a></p>
</li>
<li><p><a target="_blank" href="https://swr.vercel.app/">https://swr.vercel.app/</a></p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/v3/">https://tanstack.com/query/v3/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Memory leak in React JS application]]></title><description><![CDATA[Memory leaks or unintentional memory growth in a React application can be risky, potentially causing the browser tab—or even the entire browser—to crash.
Recently, I encountered this issue firsthand. We were working on a React application that displa...]]></description><link>https://blog.msar.me/memory-leak-in-react-js-application</link><guid isPermaLink="true">https://blog.msar.me/memory-leak-in-react-js-application</guid><dc:creator><![CDATA[Saiful Alam]]></dc:creator><pubDate>Fri, 08 Dec 2023 06:26:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/nuc3NFB_6po/upload/79c8866f03034a97be8324c4d98c839e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Memory leaks or unintentional memory growth in a React application can be risky, potentially causing the browser tab—or even the entire browser—to crash.</p>
<p>Recently, I encountered this issue firsthand. We were working on a React application that displayed numerous charts across multiple pages. On each page, there were typically 5-7 charts, all powered by <a target="_blank" href="https://echarts.apache.org">Apache ECharts</a>.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Consider the example chart below. We had six such charts on a single page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702014525727/aee0926a-62a8-48c1-bd03-b9dc800356b4.png" alt="Example Chart" /></p>
<p>Each chart had customizable options, allowing users to modify the x-axis length, y-axis scale, and other parameters.</p>
<p>The application would load once and then remain idle until refreshed. An API call was made every minute to update the chart data automatically. With six charts, this meant that each chart could make one or two API calls per minute, and the page could stay idle for 7-30 days.</p>
<p>The component structure looked like this:</p>
<pre><code class="lang-bash">SitePage
├── ReactGridLayout
│   ├── Components loop
│   │   ├── SiteChartContainer
│   │   ├── API call
│   │   │   ├── DataChart
│   │   │   └── SingleValue
│   │   │   └── ChartSettings
</code></pre>
<p>Within the <code>DataChart</code>, we had additional child components like <code>SingleValue</code> and <code>ChartOptions</code>.</p>
<p>The issue arose because every time a new API call was made, the <code>SingleValue</code> component was re-rendered. We monitored the memory usage and noticed that it increased by approximately 1MB every 10 minutes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702014692582/d0a33271-4df0-4d48-98af-c7df184955a0.png" alt="Memory Usage" /></p>
<p>After one or two days—or sometimes after 7+ days—the memory usage would increase by ~1GB, eventually causing the tab (and sometimes the entire browser) to crash.</p>
<h2 id="heading-the-solutions">The Solutions</h2>
<p>When the browser crashed, we began a thorough investigation to identify the root cause of the problem. It became evident that the application's memory usage was gradually increasing to an unsustainable level.</p>
<h3 id="heading-identifying-the-issue">Identifying the Issue</h3>
<p>In our React application, we had numerous event listeners, such as click and mouse event listeners, as well as some timer functions that weren't being cleared when a component unmounted. As a result, the memory consumed by these listeners, timers, and hooks wasn't being released, and the JavaScript garbage collector wasn't clearing them either.</p>
<p>Additionally, we discovered issues with the chart's tooltip formatting, which relied on a closure function. This caused the entire series to depend on certain calculations.</p>
<p>After identifying these issues, we were able to take action by reviewing every component related to this page and making the necessary updates.</p>
<h2 id="heading-optimizing-the-component-hierarchy">Optimizing the Component Hierarchy</h2>
<p>As you can see from our initial component hierarchy, we decided to refactor it—particularly the <code>SiteChartContainer</code> component.</p>
<p>Initially, we used the React Context API to pass data to child components. However, we found that the Context API wasn't ideal in this case, as it caused the entire component tree to re-render whenever the context value changed. We decided to switch to Zustand for state management and used React's <code>memo</code> to optimize child component rendering.</p>
<h3 id="heading-01-the-new-component-hierarchy">01 - The New Component Hierarchy</h3>
<pre><code class="lang-bash">SitePage
├── ReactGridLayout
│   ├── Components loop
│   │   ├── SiteChartContainer
│   │   ├── ├── DataFetcher
│   │   │   ├── DataChartDom
│   │   │   └── DataChartOptions
│   │   │   └── SingleValue
│   │   │   └── ChartSettings
</code></pre>
<p>We restructured the <code>SiteChartContainer</code> component, separating it into sibling components instead of nested components. Data is now passed to child components through the Zustand store, ensuring that only the relevant component re-renders when the data changes.</p>
<p><strong>Key Components:</strong></p>
<ul>
<li><p><strong>SiteChartContainer</strong>: Contains all initialization and sibling components.</p>
</li>
<li><p><strong>DataFetcher</strong>: Fetches data from the API and stores it in Zustand.</p>
</li>
<li><p><strong>DataChartDom</strong>: Renders the eChart using React DOM references.</p>
</li>
<li><p><strong>DataChartOptions</strong>: Sets initial eChart options and updates them when the data changes.</p>
</li>
<li><p><strong>SingleValue</strong>: Renders the latest chart value from the Zustand store.</p>
</li>
<li><p><strong>ChartSettings</strong>: Manages chart settings and updates options accordingly.</p>
</li>
</ul>
<h3 id="heading-02-adding-clean-up-functionality-timers-amp-listeners">02 - Adding Clean-Up Functionality: Timers &amp; Listeners</h3>
<p>We also refactored event listeners and timers, using the <code>useEffect</code> hook to add these functionalities and ensure they were cleared when the component unmounted.</p>
<p>JavaScript provides built-in functions like <code>setTimeout</code> for executing code asynchronously after a specific duration, <code>setInterval</code> for regular intervals, and <code>addEventListener</code> for DOM event manipulation. However, if not properly cleared, these can cause memory issues.</p>
<p>Here's a simple example of a listener with clean-up functionality:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> listener = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// handle click event</span>
  };
  <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'click'</span>, listener);
  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">'click'</span>, listener);
  };
}, []);
</code></pre>
<p>If you don't remove these listeners during component unmount, they will persist in memory, causing problems with each re-render.</p>
<p>Another example of clearing timer functions:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> timer = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// perform some action</span>
  }, <span class="hljs-number">1000</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">clearInterval</span>(timer);
  };
}, []);
</code></pre>
<p>Always ensure that you remove or clear timers and event listeners to avoid memory issues.</p>
<h3 id="heading-03-refactoring-the-chart-tooltip">03 - Refactoring the Chart Tooltip</h3>
<p>This was a tricky part. We discovered that the chart tooltip wasn't releasing memory, which turned out to be an internal issue with eCharts (<a target="_blank" href="https://github.com/apache/echarts/issues/10130">reference issue</a>). To mitigate this, we passed the necessary data to the series value for the tooltip during the data calculation in the <code>DataChartOptions</code> component and used a format function to handle the tooltip formatting.</p>
<pre><code class="lang-js">type ChartSeriesData = [
    number, <span class="hljs-comment">// timestamp</span>
    number, <span class="hljs-comment">// value</span>
    string, <span class="hljs-comment">// unit</span>
    string|object, <span class="hljs-comment">// necessary data for tooltip</span>
];
</code></pre>
<p>By decoupling the tooltip from the series data, the memory was successfully released.</p>
<h2 id="heading-the-result">The Result</h2>
<p>After optimization, we observed that memory usage no longer increased significantly, and the application has been running smoothly for over 20+ days.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701440861124/f9fd556e-d765-4a00-be83-4c995c85b24b.png" alt="Improved Memory Usage" /></p>
<p>We also refactored the Material-UI theme switcher functionality. Previously, switching between light and dark themes caused the entire page to re-render.</p>
<h2 id="heading-javascript-garbage-collection-and-manual-clean-up">JavaScript Garbage Collection and Manual Clean-Up</h2>
<p>JavaScript employs a form of automatic memory management known as <a target="_blank" href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)">garbage collection</a>. The garbage collector monitors memory allocation, reclaiming memory that is no longer needed. However, since the problem of automatically identifying unused memory is undecidable, garbage collectors provide only an approximate solution.</p>
<p>To avoid memory issues, keep the following checklist in mind:</p>
<ol>
<li><p>Timers and Callbacks</p>
</li>
<li><p>Closures</p>
</li>
<li><p>Event Listeners</p>
</li>
<li><p>Detached DOM Elements</p>
</li>
<li><p>API Calls (e.g., React Query, Axios)</p>
</li>
</ol>
<p><strong>Tools for Testing Memory Leaks:</strong></p>
<ul>
<li><p>Browser DevTools - Memory Tab</p>
</li>
<li><p>Memlab by Meta</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This issue taught us a lot, including that the React Context API may not always be the best solution for data passing. We also deepened our understanding of Zustand as a state management tool.</p>
<p>The solutions outlined here may seem straightforward, but they came after extensive research and development. This was a team effort—the "Avengers" of development! 😎</p>
]]></content:encoded></item></channel></rss>