<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amartya Chowdhury</title>
    <description>The latest articles on DEV Community by Amartya Chowdhury (@aetherflux).</description>
    <link>https://dev.to/aetherflux</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1203703%2F8dc4b75a-342c-418d-88f0-cddb051bbee7.png</url>
      <title>DEV Community: Amartya Chowdhury</title>
      <link>https://dev.to/aetherflux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aetherflux"/>
    <language>en</language>
    <item>
      <title>Demystifying QR Codes</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Fri, 21 Aug 2026 16:37:29 +0000</pubDate>
      <link>https://dev.to/aetherflux/demystifying-qr-codes-1fio</link>
      <guid>https://dev.to/aetherflux/demystifying-qr-codes-1fio</guid>
      <description>&lt;p&gt;We have all used QR codes at some point of our life. UPI payments in stores, scanning QRs on posters to register for an event, sometimes even restaurants where the entire menu is stored on a QR code. But have you ever wondered how it works? If your answer is no, don't worry. I was the same lol. But I suddenly felt like going into this rabbithole, and it was a crazy experience to say the least.&lt;/p&gt;

&lt;p&gt;Let's start from the beginning. QR stands for Quick Response. It was first created back in 1994 at a Japanese automobile company to track the types and numbers of different parts. But with the advent of the 2000s and the Internet, people soon found the potential of QR codes left untouched, and now its become a common part in many systems.&lt;/p&gt;

&lt;p&gt;A QR code can seem random at first, but every black and white pixel carries a meaning. It contains some static patterns, like the three 7x7 squares at the top-left, top-right, and bottom-left corners, which are used by a scanner to determine the extent of the code to be scanned. There are predefined rules to placing information on the grid, and we will discuss them as we progress further in this blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Encoding text into bytes
&lt;/h2&gt;

&lt;p&gt;A QR code is a bunch of black and white pixels. Every dark pixel is 1 and every light pixel is 0. So, the input text must be encoded into binary bytes so that it can be engraved into the grid.&lt;/p&gt;

&lt;p&gt;There are a few different modes of encoding, but the ones we will talk about are the following three:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Numeric mode&lt;/strong&gt;: It is the most efficient mode to encode text containing only numeric values. It uses 10 bits to store 3 digits (2^10 = 1024 &amp;gt; 999), 7 bits to store 2 digits (2^7 = 128 &amp;gt; 99), and 4 bits to store 1 digit (2^4 = 16 &amp;gt; 9).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Alphanumeric mode&lt;/strong&gt;: This mode has a character set of 45 elements, including uppercase characters A-Z, digits 0-9, space, $, %, *, +, -, ., /, :. It uses 11 bits to store 2 characters ((45 x first_char) + second_char), and 6 bits to store 1 character (2^6 = 64 &amp;gt; 45).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Byte mode&lt;/strong&gt;: This mode stores every character as a single byte, according to ISO 8859-1 character set, or if supported, UTF-8. Here, every character is stored with 8 bits (1 byte).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We would write the code in a way so that it can automatically determine the best encoding mode to use, as per the characters present in the input text.&lt;/p&gt;

&lt;p&gt;It is time to construct the message data bytes. The first four bits represent the encoding mode, as follows:&lt;br&gt;&lt;br&gt;
1. &lt;strong&gt;Numeric mode&lt;/strong&gt;: 0001&lt;br&gt;&lt;br&gt;
2. &lt;strong&gt;Alphanumeric mode&lt;/strong&gt;: 0010&lt;br&gt;&lt;br&gt;
3. &lt;strong&gt;Byte mode&lt;/strong&gt;: 0100&lt;/p&gt;

&lt;p&gt;Next would be to encode the number of characters in the input (i.e. character count of input text). Different versions of QR code specify the number of bits the character count must be represented it. I highly recommend readers to go through &lt;a href="https://www.thonky.com/qr-code-tutorial/" rel="noopener noreferrer"&gt;Thonky's QR Code Tutorial&lt;/a&gt; for detailed information.&lt;/p&gt;

&lt;p&gt;After the character count, its time to finally push the encoded bytes of input text. At the end of these bytes, terminator bits are added, which are 4 0s. If however, there isn't enough space left for 4 0s, the spec says to add only the number of 0s that are available.&lt;/p&gt;

&lt;p&gt;After adding the terminator bits, if the number of filled bits is not a multiple of 8, add more 0s to pad it up to the next nearest multiple. Following that, we add bytes 236 and 11 alternatively until the full allocated message data bytes are full.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: The Math (and correcting errors)
&lt;/h2&gt;

&lt;p&gt;This is where the math starts. We start with Galois Field. A Galois Field GF(p) is just a set of numbers that follow all general properties (closure, associative, etc) of all operations like addition, subtraction, multiplication, division. In a field GF(p), every operation is mod p.&lt;/p&gt;

&lt;p&gt;For example, let's take GF(5). The set of numbers would be &lt;code&gt;{0, 1, 2, 3, 4}&lt;/code&gt;. Addition: &lt;code&gt;a + b (mod 5)&lt;/code&gt;. For instance, adding 1 and 3 would be &lt;code&gt;1 + 3 = 4 mod 5 = 4&lt;/code&gt;. For numbers greater than 4: &lt;code&gt;2 + 7 = 9 mod 5 = 4&lt;/code&gt;. This follows for all operations, wrapping every operation result into the set of numbers provided.&lt;/p&gt;

&lt;p&gt;In our case, we use GF(2^8) since we are working with bytes, so the possible values are 0 to 255, decimal values possible in 8 bits (1 byte).&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiplication in GF(2^8)
&lt;/h3&gt;

&lt;p&gt;In regular arithmetic, multiplying two 8-bit numbers can go up to 65025. To fit all results within 0 to 255, numbers in GF(2^8) are treated as polynomials where (n+1)th bit is the coefficient of x^n (e.g. 8th bit - x^7, 3rd bit - x^2, 1st bit - x^0 (constant term)). For example, 13 in binary is 00001101, represented as a polynomial as follows:&lt;br&gt;&lt;br&gt;
&lt;code&gt;1.x^3 + 1.x^2 + 0.x + 1 = x^3 + x^2 + 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To keep multiplication bounded within 0-255 (8 bits), we multiply these polynomials using standard algebra and take the remainder after dividing by a &lt;em&gt;primitive polynomial&lt;/em&gt; (an irreducible polynomial that acts as the prime number for field restriction).&lt;/p&gt;

&lt;p&gt;For QR codes, the standard primitive polynomial specified by ISO/IEC 18004 is &lt;code&gt;x^8 + x^4 + x^3 + x^2 + 1&lt;/code&gt; (represented as hex 0x11D or decimal 285).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Addition and subtraction in GF(2^8) are both equivalent to XORing the two numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast way: Log and Antilog Tables
&lt;/h3&gt;

&lt;p&gt;Doing full polynomial long divison for every single multiplication during Reed-Solomon generation would destroy performance. Instead we use a property: a primitive element g (generator) can generate every non-zero element in the field through exponentiation. For QR codes, we use g = 2.&lt;/p&gt;

&lt;p&gt;By pre-computing two 256-element lookup tables (an exponential (antilog) table and a log table), we can convert heavy polynomial multiplication into simple integer addition:&lt;br&gt;&lt;br&gt;
&lt;code&gt;a x b = exp((log(a) + log(b)) mod 255)&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Correction Levels
&lt;/h3&gt;

&lt;p&gt;Before moving on to actually error correction, we need to discuss the different error correction levels. QR codes have four different levels, each having a different number of error correction bytes to be added depending on the version of QR code. The four levels are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;L (Low)&lt;/strong&gt;: 7% error correction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;M (Medium)&lt;/strong&gt;: 15% error correction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Q (Quartile)&lt;/strong&gt;: 25% error correction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;H (High)&lt;/strong&gt;: 30% error correction&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generating Error Correction Bytes (Reed Solomon Codes)
&lt;/h3&gt;

&lt;p&gt;This is the error correction method we will be using for QR codes. Reed Solomon error correction works by taking your message bytes, treating them as coefficients of a high-degree message polynomial M(x), and finding the remainder when divided by generator polynomial G(x). The remainder R(x) contains the actual error correction bytes to be appended to the original message bytes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Generator Polynomial G(x)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A generator polynomial for k error correction codewords is created by expanding the factors (x-2^0)(x-2^1)...(x-2^(k-1)) using GF(2^8) arithmetic. For example, for k=7 error correction bytes:&lt;br&gt;&lt;br&gt;
&lt;code&gt;G(x) = (x-2^0)(x-2^1)...(x-2^6)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Expanding this gives a polynomial with 8 terms whose coefficients are elements in GF(2^8).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Polynomial Synthetic Division&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To compute the remainder, we perform synthetic division of M(x).x^k by G(x) inside our field:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Shift the message polynomial left by k positions (multiplying by x^k) to leave k zero bytes at the end for error correction bytes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step through each byte of the message:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Take the first byte of the current remainder buffer as a multiplier scale factor S.&lt;/li&gt;
&lt;li&gt; If S != 0, multiply each coefficient of G(x) by S using our log/exp lookup tables.&lt;/li&gt;
&lt;li&gt; XOR the scaled generator polynomial into the remainder buffer.&lt;/li&gt;
&lt;li&gt; Shift the remainder buffer left by 1 position.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once all message bytes are processed, values remaining in the remainder buffer are the exact Reed Solomon Error Correction Bytes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And we are done! We now have the error correction bytes, and we append it to the end of the message bytes we had previously.&lt;/p&gt;

&lt;p&gt;For implementation details, you can refer to my QR code generator in Rust, linked in a later section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: Masks and Format String
&lt;/h2&gt;

&lt;p&gt;We are almost at the end. The last phase is to choose a mask and create the format string. A mask is essentially a formula which decides which pixels on the grid should be XORed. The main reason of using a mask is to reduce unnecessary concentration of same-color pixels and other factors that can affect the ability of scanners to properly scan a QR code.&lt;/p&gt;

&lt;p&gt;There are 8 different masks, ranging from 0 to 7 (000 to 111). I will not be going through all the formulae here, but again, I recommend you to go through Thonky's guide for details on this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing a mask: Penalty Rules
&lt;/h3&gt;

&lt;p&gt;All the 8 masks are applied on to the grid, each is checked against four penalty rules, and the mask with the least penalty score is finalized. The beauty of masks is that they are their own negatives, i.e. XORing a mask onto a grid masks it, XORing it again gives us back the original data grid.&lt;/p&gt;

&lt;p&gt;The four penalty rules are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Continuous runs of same-color modules of length 5 or more, in a row or a column.&lt;br&gt;&lt;br&gt;
Score: 3 + (n - 5) per run of length n &amp;gt;= 5.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;2x2 blocks of same-color modules.&lt;br&gt;&lt;br&gt;
Score: 3 points per 2x2 block.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Patterns matching 1011101 surrounded by 4 light modules (finder-like false positives).&lt;br&gt;&lt;br&gt;
Score: 40 points per occurrence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proportion of dark vs light modules deviating from 50%.&lt;br&gt;&lt;br&gt;
Score: 10 x floor(abs(dark_percent - 50) / 5).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Format String
&lt;/h3&gt;

&lt;p&gt;Once a mask is selected, we need to encode metadata directly into the QR code so that a scanner knows which error correction level and mask was used.&lt;/p&gt;

&lt;p&gt;The format string is 15-bits long, with 5 data bits and 10 error correction bits. Out of the 5 data bits, 2 bits represent error correction level, and 3 bits represent the mask used (000-111). For error correction level:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;L -&amp;gt; 01&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;M -&amp;gt; 00&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Q -&amp;gt; 11&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;H -&amp;gt; 10&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 10 error correction bits are generated with the help of BCH codes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BCH Error Correction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the format string is critical for decoding the entire QR code, it gets its own error correction using a BCH (Bose-Chaudhuri-Hocquenghem) (15, 5) code. To generate the 10 error correction bits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Shift the 5-bit value left by 10 bits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Perform polynomial division modulo 2 using generator polynomial &lt;code&gt;G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1&lt;/code&gt; (which is 0x537 or 10100110111).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The 10-bit remainder is appended to the original 5 bits to form a 15-bit codeword.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Masking the format string&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To ensure that format strings don't accidentally contain long runs of all zeros or all ones which could confuse scanners, the final 15-bit string is XORed with a fixed mask: &lt;code&gt;101010000010010&lt;/code&gt; or &lt;code&gt;0x5412&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The 15-bit format string is written into two redundant locations on the QR code to survive physical damage or corruption:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Around the top-left finder pattern&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Divided between top-right and bottom-left finder patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Remember to skip the dark module at coordinate &lt;code&gt;(4 * version + 9, 8)&lt;/code&gt; which always remains dark (as per QR code specification).&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Everything: The Battle Wounds I Have
&lt;/h2&gt;

&lt;p&gt;Writing &lt;code&gt;qred&lt;/code&gt;, my own implementation of a QR code generator, wasn't a smooth ride in the slightest. I faced quite a few brain-frying bugs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bit placement order&lt;/strong&gt;: The issue wasn't in error correction math or matrix generation. Everything was working perfectly, but turns out I was writing the bits of the format string in reverse order. Bit 14 in the place of bit 0, bit 13 at bit 1, and so on. That alone took one day for me to find, and I couldn't even find it alone (massive Claude W).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Math&lt;/strong&gt;: I'm surprised I even managed to finish this project. Given my background of not liking math (or so I thought), I expected face much more trouble. Thankfully, after the first weird bug found at the remainder generation of Reed Solomon, I started writing unit tests for every file, ensuring the code of the current phase is fully functional before moving on to the next phase with a broken foundation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;I implemented it in Rust BTW (I use Arch BTW)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;I didn't leave it after just writing everything. I wanted to see the fruits of my labor. So for the first time in any of my Rust projects (don't bully me, I'm pretty new to this field), I downloaded criterion, set up benchmark functions, and started measuring performance. Here's the results, analyze them and judge whether they're good or bad, because I'm leaving absolutely no comments here:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Execution Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Matrix Generation Only&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pure Bit Matrix&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;179.92 µs&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Default Image Save&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard PNG Export&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;237.19 µs&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Single Custom Color&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom Foreground&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;274.65 µs&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dual Custom Colors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom Fore &amp;amp; Background&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;281.26 µs&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I Left Out
&lt;/h2&gt;

&lt;p&gt;Of course, I didn't touch every little detail in this small blog. I have left out some parts, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Static patterns like finder patterns, timing patterns, alignment patterns, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exact locations of format strings, message and error correction bytes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The order of reading the data bytes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;To dive deeper into this rabbit hole, I recommend these sources as I used them myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.thonky.com/qr-code-tutorial/" rel="noopener noreferrer"&gt;Thonky's QR Code Tutorial&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders" rel="noopener noreferrer"&gt;Reed Solomon Codes for Coders&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The full PDF of ISO/IEC 18004&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Like me?
&lt;/h2&gt;

&lt;p&gt;Well then, you're not alone (I like myself too)! Check out more about me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;: &lt;a href="https://linkedin.com/in/amartya-chowdhury" rel="noopener noreferrer"&gt;https://linkedin.com/in/amartya-chowdhury&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/aether-flux" rel="noopener noreferrer"&gt;https://github.com/aether-flux&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;qred&lt;/code&gt; &lt;strong&gt;Crates.io&lt;/strong&gt;: &lt;a href="https://crates.io/crates/qred" rel="noopener noreferrer"&gt;https://crates.io/crates/qred&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A bonus flex: Wanna see my implementation in practice? Scan this QR generated by qred to get to my portfolio:&lt;/p&gt;

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

</description>
      <category>qr</category>
      <category>rust</category>
      <category>systems</category>
    </item>
    <item>
      <title>You Don't Have to Grind LeetCode</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Wed, 17 Sep 2025 15:23:57 +0000</pubDate>
      <link>https://dev.to/aetherflux/you-dont-have-to-grind-leetcode-3a4o</link>
      <guid>https://dev.to/aetherflux/you-dont-have-to-grind-leetcode-3a4o</guid>
      <description>&lt;p&gt;Yes, you read it right. Everyone says "you should do 500 problems on LeetCode at least". And sure, to some extent, it is helpful. But it's not everything. You don't need to follow the same path if you see a bunch of people on Twitter/Linkedin doing a "100 days of code" challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are you inconsistent, no matter how hard you try?
&lt;/h3&gt;

&lt;p&gt;Have you ever felt like no matter how much you try to be consistent, try to do at least one LeetCode problem a day, you just can't keep it up for more than a week? Do you have to force yourself just to be consistent?&lt;/p&gt;

&lt;p&gt;So let's look at it from a different perspective. Let's say, like me, you are someone who hates the subject of biology. I have always hated that subject, to the point that I couldn't bring myself to keep my eyes open for 2 minutes without trying to force myself awake again. And I was a student who never slept in study sessions. No matter how much I forced myself to study biology, I could never do it well.&lt;/p&gt;

&lt;p&gt;Sounds similar? Because it is. Maybe underneath all of the Twitter/Linkedin posts and flexes of LeetCode grinds and coding challenges, it has never even crossed your mind that maybe this LeetCode grind is just not what you love.&lt;/p&gt;

&lt;h3&gt;
  
  
  No LeetCode? Then what?
&lt;/h3&gt;

&lt;p&gt;It is very much possible that you are the kind of person who just isn't built for LeetCode grinds. And that isn't necessarily a bad thing; it's just a different style. Maybe you are built for LeetCode grinds, or maybe you are someone who likes to see immediate results, someone who prefers building a website or an app to see their work in action, someone who likes to handle domains and manage servers, maybe even someone who's just a complete nerd that likes Linux and Vim (don't worry, I'm with you 😔).&lt;/p&gt;

&lt;p&gt;Everybody has a different thing they love. Taking myself as an example again, I was never someone who liked solving LeetCode problems. That was primarily because I couldn't see any effects of my code immediately. I had always preferred building websites where I can see the fruits of my action. Even now, I am very development-oriented, although I don't really like frontend dev (sorry fellow frontend devs 😔). I currently build backend systems and infra/devtools, but the concept is still the same: &lt;strong&gt;building something actually useful and not just blindly solving random problems&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, is LeetCode (or any problem solving) useless?
&lt;/h3&gt;

&lt;p&gt;This is where most people misunderstand. I am not saying that LeetCode grind, or any kind of problem solving, is useless. It's the most important, in fact. DSA is a major factor in you becoming a better developer. &lt;/p&gt;

&lt;p&gt;However, it's not essential that you learn DSA through just LeetCode problems. DSA shines the most when it's applied in real-life products. For example, build something yourself, maybe a backend or some library, and experiment about how to make it more efficient. Maybe learn about which algorithms would be better and more efficient, or just design one yourself. Maybe use a linked list instead of an array in some cases. That is where DSA shines. That is where real &lt;strong&gt;problem-solving&lt;/strong&gt; takes place.&lt;/p&gt;

&lt;p&gt;I'll put a little flex of myself again. I was working on my backend framework (&lt;em&gt;Rensa&lt;/em&gt;), and my first draft of the routing system used plain arrays to store routes and route handlers. As a result, whenever a user would hit a route on the server, it would take &lt;strong&gt;O(n)&lt;/strong&gt; time to search for the route (&lt;em&gt;n&lt;/em&gt; is the number of routes) and it's handler and call it. Very inefficient for good backend servers. So, I researched a bit and stumbled upon &lt;strong&gt;Tries&lt;/strong&gt;. Implemented route storage with that, and boom, the time complexity reduced to &lt;strong&gt;O(l)&lt;/strong&gt;, where &lt;em&gt;l&lt;/em&gt; is the length of route. It doesn't depend on the number of routes registered, which is better as a server increases in size. Then a sudden enlightenment hit me all of a sudden, and I implemented a hybrid &lt;strong&gt;Trie+HashMap&lt;/strong&gt; for storing routes. Now, although theoretically the time complexity was still &lt;strong&gt;O(l)&lt;/strong&gt;, but for completely static routes (like /home/dashboard, unlike /user/:userId), it practically worked in &lt;strong&gt;O(1)&lt;/strong&gt; (constant) time, thanks to the newly introduced HashMap. (Read more about the entire approach &lt;a href="https://dev.to/aetherflux/the-hidden-complexity-of-routing-why-your-requests-take-longer-than-they-should-5bbf"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;As you can see, you can start something small with just as much knowledge as you have right now, and with time and research you can keep on improving your solutions bit-by-bit. &lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion?
&lt;/h3&gt;

&lt;p&gt;The conclusion is just that &lt;strong&gt;you don't need to feel guilty if you can't stay consistent, you just need to change your ways&lt;/strong&gt;. Sure, LeetCode problems are definitely not useless and they do teach you about how many commonly encountered problems can be solved. But it's not everything, because ultimately, you will be having to build systems and not be only solving problems all your career.&lt;/p&gt;

&lt;p&gt;So, the next time you feel demotivated because of inconsistency, just remember this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have to force yourself to do something, it probably isn't for you. Time to change your ways.&lt;br&gt;
&lt;strong&gt;Consistency will automatically follow you if you're doing something you truly love.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Time for some personal promotion, so before you leave, make sure to follow me on &lt;a href="https://x.com/aetheros__" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/amartya-chowdhury" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>motivation</category>
      <category>programming</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>Building Profig - A Config Framework</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Thu, 07 Aug 2025 15:33:37 +0000</pubDate>
      <link>https://dev.to/aetherflux/building-profig-a-config-framework-36o1</link>
      <guid>https://dev.to/aetherflux/building-profig-a-config-framework-36o1</guid>
      <description>&lt;p&gt;I've worked with config files for a long time. Be it for my own tools/projects or for using it for other purposes, I have needed to manage configs manually for a long time. Until I discovered that there exist literal config managers, and that I had been wasting my efforts for absolutely no reason.&lt;/p&gt;

&lt;p&gt;I found that there were a bunch of good options available for config managers in JavaScript (NPM). However, the same is not the case for Rust. Here, there are limited options, popular ones being &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;config-manager&lt;/code&gt; and &lt;code&gt;figment&lt;/code&gt;. And so I set out to work on a new project, and here it is:&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Profig?
&lt;/h2&gt;

&lt;p&gt;Introducing &lt;strong&gt;Profig&lt;/strong&gt;, a config &lt;em&gt;framework&lt;/em&gt;, that removes the &lt;em&gt;Con&lt;/em&gt; in &lt;em&gt;Config&lt;/em&gt;. This is still in very early development stages, and I've only released just &lt;code&gt;v0.1&lt;/code&gt;, but I think it's still usable in small and maybe even medium sized projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Profig is currently &lt;code&gt;v0.1&lt;/code&gt;, and it has the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Macros like &lt;code&gt;#[derive(Profig)]&lt;/code&gt; and &lt;code&gt;#[profig(...)]&lt;/code&gt; to define config schema structs&lt;/li&gt;
&lt;li&gt;Enforce only certain file formats to be allowed to load data from, using &lt;code&gt;#[profig(format="json,toml")]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Every field of the struct will have its own metadata, defined via &lt;code&gt;#[profig(min="..", max="..", default="..", regex=r"..", doc="..")]&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Data can be loaded from any file using &lt;code&gt;AppConfig::load("filename.ext")&lt;/code&gt; (assuming AppConfig is the name of the struct defined), and it returns an object of type AppConfig&lt;/li&gt;
&lt;li&gt;It validates every field data according to the metadata (&lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;regex&lt;/code&gt; etc.) and fills a field with the &lt;code&gt;default&lt;/code&gt; value if applicable&lt;/li&gt;
&lt;li&gt;Sample config files can be generated via &lt;code&gt;AppConfig::sample_config("sample.yaml")&lt;/code&gt; using the data available in the metadata of the fields (defined using &lt;code&gt;#[profig(...)]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Documentation can be generated automatically using &lt;code&gt;AppConfig::generate_docs("docs.md")&lt;/code&gt; which generates a markdown file using the &lt;code&gt;doc&lt;/code&gt; metadata of every field&lt;/li&gt;
&lt;li&gt;Multiple formats: JSON, TOML, YAML (all as their own features)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;All these features can seem confusing and overwhelming at first, even though they aim to greatly enhance DX. So, let's do a bit of practical.&lt;/p&gt;

&lt;p&gt;Let's imagine a situation where we need the user to define a config file which contains some data like host name, port number, user email, and the number of worker threads. The user may have a JSON or a YAML file as a config file. Using this data, our Rust code is supposed to authenticate/validate the details and then start a server or do something else, as required. Suppose that we are to build a CLI, and we need the details from a config file, as mentioned. Let's see how simple it is to achieve with &lt;strong&gt;Profig&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before anything else, let us first add the crate to our project. Since we need JSON and YAML configs, we will enable those features while installing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add profig &lt;span class="nt"&gt;--features&lt;/span&gt; &lt;span class="s2"&gt;"json,yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we define a schema for the config file. To define the schema, we use the attributes provided by Profig as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Profig)]&lt;/span&gt;
&lt;span class="nd"&gt;#[profig(format=&lt;/span&gt;&lt;span class="s"&gt;"json, yaml"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HostConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;#[profig(min=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Number of worker threads"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(default=&lt;/span&gt;&lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Name of the host"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(min=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"65536"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Port number to listen to"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(regex=&lt;/span&gt;&lt;span class="s"&gt;r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Email address of the user"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all we need to do in order to define the schema/format of the config files. We specified formats as &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;yaml&lt;/code&gt; as those are the only ones allowed. Now to read data from a file, say &lt;code&gt;config.yaml&lt;/code&gt;, we can do so as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;confData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config.yaml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// All data can now be accessed as confData.email, confData.host etc&lt;/span&gt;
  &lt;span class="c1"&gt;// because this returns an object of type HostConfig.&lt;/span&gt;
  &lt;span class="c1"&gt;// You can use this data for any further logic implementation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! You have successfully loaded and used data from config files!&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Config
&lt;/h3&gt;

&lt;p&gt;You can also generate a sample config file in a single line, using the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sample_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the following type of sample file (JSON here):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threads"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hostname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REQUIRED; must match ^[a-z0-9._%+-]+@[a-z0-9.-]+&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;[a-z]{2,4}$"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Documentation Generation
&lt;/h3&gt;

&lt;p&gt;That's not all. You can also generate a documentation for your defined config structure in a single line! Just call the following method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;generate_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docs.md"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it will generate you a &lt;code&gt;markdown&lt;/code&gt; file filled with data like field name, field data type, and a field help/doc line if provided (via the &lt;code&gt;doc="..."&lt;/code&gt; value in the field-level metadata).&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠 Tech Dive
&lt;/h2&gt;

&lt;p&gt;For the bit more nerdy humans like myself, let's talk a bit about the tech. This project uses Rust (no s**t Sherlock), along with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serde, serde_json for storing and validating the data&lt;/li&gt;
&lt;li&gt;serde_json, serde_yaml and toml crates to load data from different config file types&lt;/li&gt;
&lt;li&gt;Procedural macros to make the &lt;code&gt;#[derive(Profig)]&lt;/code&gt; and &lt;code&gt;#[profig(...)]&lt;/code&gt; attributes to make DX smoother&lt;/li&gt;
&lt;li&gt;Feature flags for every file format to avoid unnecessarily bloating the crate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an architecture/design of the entire working or flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD5622AQFvA8-_ZLcwPA%2Ffeedshare-shrink_800%2FB56Zh63vkHG4Ak-%2F0%2F1754408098595%3Fe%3D1757548800%26v%3Dbeta%26t%3DOFh-y1BfHQLSYmHTs2BvdhDTENfqoF3to6LSMMHiWvo" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD5622AQFvA8-_ZLcwPA%2Ffeedshare-shrink_800%2FB56Zh63vkHG4Ak-%2F0%2F1754408098595%3Fe%3D1757548800%26v%3Dbeta%26t%3DOFh-y1BfHQLSYmHTs2BvdhDTENfqoF3to6LSMMHiWvo" alt="profig architecture" width="800" height="251"&gt;&lt;/a&gt;️ &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;All in all, Profig is a config framework that I plan to keep building and improving as time sees. It is in very early stages right now, being just &lt;code&gt;v0.1&lt;/code&gt;, so there will be quite some changes before even &lt;code&gt;Profig v1&lt;/code&gt; is launched.&lt;/p&gt;

&lt;p&gt;In the meanwhile, I would love any and all feedbacks and advice.&lt;/p&gt;

&lt;p&gt;Please do try it for yourself if possible:&lt;br&gt;
🦀 &lt;a href="https://crates.io/crates/profig" rel="noopener noreferrer"&gt;Crates.io&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/aether-flux/profig" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more updates, follow me on:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/amartya-chowdhury" rel="noopener noreferrer"&gt;LINKEDIN&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/aetheros__" rel="noopener noreferrer"&gt;TWITTER&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building Profig - A Config Framework</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Thu, 07 Aug 2025 15:33:37 +0000</pubDate>
      <link>https://dev.to/aetherflux/building-profig-a-config-framework-1cca</link>
      <guid>https://dev.to/aetherflux/building-profig-a-config-framework-1cca</guid>
      <description>&lt;p&gt;I've worked with config files for a long time. Be it for my own tools/projects or for using it for other purposes, I have needed to manage configs manually for a long time. Until I discovered that there exist literal config managers, and that I had been wasting my efforts for absolutely no reason.&lt;/p&gt;

&lt;p&gt;I found that there were a bunch of good options available for config managers in JavaScript (NPM). However, the same is not the case for Rust. Here, there are limited options, popular ones being &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;config-manager&lt;/code&gt; and &lt;code&gt;figment&lt;/code&gt;. And so I set out to work on a new project, and here it is:&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Profig?
&lt;/h2&gt;

&lt;p&gt;Introducing &lt;strong&gt;Profig&lt;/strong&gt;, a config &lt;em&gt;framework&lt;/em&gt;, that removes the &lt;em&gt;Con&lt;/em&gt; in &lt;em&gt;Config&lt;/em&gt;. This is still in very early development stages, and I've only released just &lt;code&gt;v0.1&lt;/code&gt;, but I think it's still usable in small and maybe even medium sized projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;Profig is currently &lt;code&gt;v0.1&lt;/code&gt;, and it has the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Macros like &lt;code&gt;#[derive(Profig)]&lt;/code&gt; and &lt;code&gt;#[profig(...)]&lt;/code&gt; to define config schema structs&lt;/li&gt;
&lt;li&gt;Enforce only certain file formats to be allowed to load data from, using &lt;code&gt;#[profig(format="json,toml")]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Every field of the struct will have its own metadata, defined via &lt;code&gt;#[profig(min="..", max="..", default="..", regex=r"..", doc="..")]&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Data can be loaded from any file using &lt;code&gt;AppConfig::load("filename.ext")&lt;/code&gt; (assuming AppConfig is the name of the struct defined), and it returns an object of type AppConfig&lt;/li&gt;
&lt;li&gt;It validates every field data according to the metadata (&lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;regex&lt;/code&gt; etc.) and fills a field with the &lt;code&gt;default&lt;/code&gt; value if applicable&lt;/li&gt;
&lt;li&gt;Sample config files can be generated via &lt;code&gt;AppConfig::sample_config("sample.yaml")&lt;/code&gt; using the data available in the metadata of the fields (defined using &lt;code&gt;#[profig(...)]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Documentation can be generated automatically using &lt;code&gt;AppConfig::generate_docs("docs.md")&lt;/code&gt; which generates a markdown file using the &lt;code&gt;doc&lt;/code&gt; metadata of every field&lt;/li&gt;
&lt;li&gt;Multiple formats: JSON, TOML, YAML (all as their own features)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;All these features can seem confusing and overwhelming at first, even though they aim to greatly enhance DX. So, let's do a bit of practical.&lt;/p&gt;

&lt;p&gt;Let's imagine a situation where we need the user to define a config file which contains some data like host name, port number, user email, and the number of worker threads. The user may have a JSON or a YAML file as a config file. Using this data, our Rust code is supposed to authenticate/validate the details and then start a server or do something else, as required. Suppose that we are to build a CLI, and we need the details from a config file, as mentioned. Let's see how simple it is to achieve with &lt;strong&gt;Profig&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before anything else, let us first add the crate to our project. Since we need JSON and YAML configs, we will enable those features while installing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add profig &lt;span class="nt"&gt;--features&lt;/span&gt; &lt;span class="s2"&gt;"json,yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we define a schema for the config file. To define the schema, we use the attributes provided by Profig as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Profig)]&lt;/span&gt;
&lt;span class="nd"&gt;#[profig(format=&lt;/span&gt;&lt;span class="s"&gt;"json, yaml"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HostConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;#[profig(min=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Number of worker threads"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(default=&lt;/span&gt;&lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Name of the host"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(min=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"65536"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Port number to listen to"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nd"&gt;#[profig(regex=&lt;/span&gt;&lt;span class="s"&gt;r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;doc=&lt;/span&gt;&lt;span class="s"&gt;"Email address of the user"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all we need to do in order to define the schema/format of the config files. We specified formats as &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;yaml&lt;/code&gt; as those are the only ones allowed. Now to read data from a file, say &lt;code&gt;config.yaml&lt;/code&gt;, we can do so as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;confData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config.yaml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// All data can now be accessed as confData.email, confData.host etc&lt;/span&gt;
  &lt;span class="c1"&gt;// because this returns an object of type HostConfig.&lt;/span&gt;
  &lt;span class="c1"&gt;// You can use this data for any further logic implementation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! You have successfully loaded and used data from config files!&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Config
&lt;/h3&gt;

&lt;p&gt;You can also generate a sample config file in a single line, using the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sample_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the following type of sample file (JSON here):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threads"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hostname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REQUIRED; must match ^[a-z0-9._%+-]+@[a-z0-9.-]+&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;[a-z]{2,4}$"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Documentation Generation
&lt;/h3&gt;

&lt;p&gt;That's not all. You can also generate a documentation for your defined config structure in a single line! Just call the following method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;HostConfig&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;generate_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"docs.md"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it will generate you a &lt;code&gt;markdown&lt;/code&gt; file filled with data like field name, field data type, and a field help/doc line if provided (via the &lt;code&gt;doc="..."&lt;/code&gt; value in the field-level metadata).&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠 Tech Dive
&lt;/h2&gt;

&lt;p&gt;For the bit more nerdy humans like myself, let's talk a bit about the tech. This project uses Rust (no s**t Sherlock), along with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serde, serde_json for storing and validating the data&lt;/li&gt;
&lt;li&gt;serde_json, serde_yaml and toml crates to load data from different config file types&lt;/li&gt;
&lt;li&gt;Procedural macros to make the &lt;code&gt;#[derive(Profig)]&lt;/code&gt; and &lt;code&gt;#[profig(...)]&lt;/code&gt; attributes to make DX smoother&lt;/li&gt;
&lt;li&gt;Feature flags for every file format to avoid unnecessarily bloating the crate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an architecture/design of the entire working or flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD5622AQFvA8-_ZLcwPA%2Ffeedshare-shrink_800%2FB56Zh63vkHG4Ak-%2F0%2F1754408098595%3Fe%3D1757548800%26v%3Dbeta%26t%3DOFh-y1BfHQLSYmHTs2BvdhDTENfqoF3to6LSMMHiWvo" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fv2%2FD5622AQFvA8-_ZLcwPA%2Ffeedshare-shrink_800%2FB56Zh63vkHG4Ak-%2F0%2F1754408098595%3Fe%3D1757548800%26v%3Dbeta%26t%3DOFh-y1BfHQLSYmHTs2BvdhDTENfqoF3to6LSMMHiWvo" alt="profig architecture" width="800" height="251"&gt;&lt;/a&gt;️ &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;All in all, Profig is a config framework that I plan to keep building and improving as time sees. It is in very early stages right now, being just &lt;code&gt;v0.1&lt;/code&gt;, so there will be quite some changes before even &lt;code&gt;Profig v1&lt;/code&gt; is launched.&lt;/p&gt;

&lt;p&gt;In the meanwhile, I would love any and all feedbacks and advice.&lt;/p&gt;

&lt;p&gt;Please do try it for yourself if possible:&lt;br&gt;
🦀 &lt;a href="https://crates.io/crates/profig" rel="noopener noreferrer"&gt;Crates.io&lt;/a&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/aether-flux/profig" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more updates, follow me on:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/amartya-chowdhury" rel="noopener noreferrer"&gt;LINKEDIN&lt;/a&gt;&lt;br&gt;
&lt;a href="https://x.com/aetheros__" rel="noopener noreferrer"&gt;TWITTER&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>tooling</category>
    </item>
    <item>
      <title>I Got Tired of Repeating the Same Commands, so I Built Jido - a Workflow Automation CLI</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Fri, 16 May 2025 18:51:44 +0000</pubDate>
      <link>https://dev.to/aetherflux/i-got-tired-of-repeating-the-same-commands-so-i-built-jido-a-workflow-automation-cli-2d2h</link>
      <guid>https://dev.to/aetherflux/i-got-tired-of-repeating-the-same-commands-so-i-built-jido-a-workflow-automation-cli-2d2h</guid>
      <description>&lt;p&gt;As a developer, you may have had moments where you find yourself running the same bunch of commands repeatedly. For example, bumping &lt;code&gt;package.json&lt;/code&gt; version, pushing to git, and publishing to NPM, whenever you wanna ship a new version of your NPM package. &lt;/p&gt;

&lt;p&gt;I was facing the same issue. And given how lazy my brain is, I wanted to make this easier and simpler. So, I built Jido.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Jido?
&lt;/h2&gt;

&lt;p&gt;Jido is a workflow automation CLI, where you can define your workflows (called &lt;code&gt;flows&lt;/code&gt;) in a config file, and run them using &lt;code&gt;npx jido flow &amp;lt;flowname&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The config file is a &lt;code&gt;jido.config.js&lt;/code&gt; in the project root. So, custom JS logic is also applicable, unlike Bash scripts.&lt;/p&gt;

&lt;p&gt;Get started with &lt;code&gt;jido&lt;/code&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jido
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Config File
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;jido.config.js&lt;/code&gt; file call the &lt;code&gt;jido()&lt;/code&gt; function and export it by default. It takes in an object as argument, which has the key &lt;code&gt;flows&lt;/code&gt; that holds an array of objects, each object defining a &lt;code&gt;flow&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Every &lt;code&gt;flow&lt;/code&gt; has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: Name of the flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; (Optional): A short description about the flow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;steps&lt;/code&gt;: Array of objects, each object defining what each step would do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each &lt;code&gt;step&lt;/code&gt; is of the following form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;run&lt;/code&gt;: The command to be run at this step (eg, 'npm run dev' or 'git push' etc).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onStart, onSuccess, onFailure&lt;/code&gt;: Optional hooks. These are functions that will be called on start, success and failure of the step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugins&lt;/code&gt;: An array of objects, where each object is a plugin. We'll talk more about this in a while.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To scaffold a basic config file, run &lt;code&gt;npx jido init&lt;/code&gt;. It'll generate the following config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jido&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jido&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/*
* Define your workflows here.
* Each flow is a series of steps with commands to run and optional hooks (onStart, onSuccess, etc) to execute.
*/&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;flows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Run the project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm install&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Installing dependencies...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dependencies installed!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;// Any plugins go here&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm run dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Starting dev server...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;// Any plugins go here&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;jido&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;Now, another fun part of Jido. Plugins. A plugin is essentially an object of the following type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Plugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Hook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Hook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;onFailure&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Hook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, its an object with any or all of these hooks, which are attached to the &lt;code&gt;step&lt;/code&gt; where the plugin is attached to.&lt;/p&gt;

&lt;p&gt;However, the recommended way of writing a plugin is to write it in a function which returns an object of the above type. This allows in custom and argument-dependent functionality of a plugin.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Plugin function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[myPlugin] Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;! Step started...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In a step in the config file:&lt;/span&gt;
&lt;span class="nl"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;myPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aether-flux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="c1"&gt;// In another step:&lt;/span&gt;
&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;myPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Now, Where Do You Use Jido?
&lt;/h3&gt;

&lt;p&gt;Well, one of the use-cases is when publishing a new version of a package to NPM or anywhere else. That was the reason why I even thought of making this CLI.&lt;/p&gt;

&lt;p&gt;There are many other applications as well. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy to vercel after a successful build.&lt;/li&gt;
&lt;li&gt;Clean + Reset project state before testing.&lt;/li&gt;
&lt;li&gt;Run local dev with custom logging and/or analytics tracking.&lt;/li&gt;
&lt;li&gt;Alert team (Slack, Discord, etc) after a successful build and deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And anywhere else really, where you find yourself running the same bunch of tasks over and over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, What Do You Think?
&lt;/h2&gt;

&lt;p&gt;I hope Jido can simplify repetitive tasks for many devs out there, thus allowing them to focus more on the fun part (aka 'coding') rather than spending so much time just pushing to github and building and deploying and all that.&lt;/p&gt;

&lt;p&gt;Do give it a chance in your workflow once. I'm sure it'd work wonders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BTW, publishing any new version of Jido is being automated by &lt;code&gt;jido&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aether-flux/jido" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FStar%2520the%2520Repo-%25F0%259F%258C%259F-brightgreen%3Fstyle%3Dfor-the-badge" alt="⭐ Star the Repo" width="156" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://npmjs.com/package/jido" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FGet%2520the%2520CLI%2520now-%25F0%259F%2593%25A6-blue%3Fstyle%3Dfor-the-badge" alt="📦 Get the CLI now" width="171" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>⚒ The Hidden Complexity Of Routing: Why Your Requests Take Longer Than They Should</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Wed, 26 Feb 2025 17:08:59 +0000</pubDate>
      <link>https://dev.to/aetherflux/the-hidden-complexity-of-routing-why-your-requests-take-longer-than-they-should-5bbf</link>
      <guid>https://dev.to/aetherflux/the-hidden-complexity-of-routing-why-your-requests-take-longer-than-they-should-5bbf</guid>
      <description>&lt;p&gt;When you type a URL and hit Enter, does it just magically find what to load in the page? Or when building your own server, just adding &lt;code&gt;app.get("/user/:id")&lt;/code&gt; will do all the magic itself?&lt;/p&gt;

&lt;p&gt;The simple answer is &lt;strong&gt;NO&lt;/strong&gt;. We usually never think much about routing and how it works, but its one of the major factors that affect the performance of a framework and a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  😮‍💨 The Normal Approach
&lt;/h2&gt;

&lt;p&gt;The simplest way we all think first when asked about how to implement routing is to use a basic &lt;code&gt;for&lt;/code&gt; loop.&lt;br&gt;
1️⃣ Store the routes in an array.&lt;br&gt;
2️⃣ When a request is made, search for that route in the array using a for loop.&lt;br&gt;
3️⃣ If the route is found, the corresponding logic is executed.&lt;/p&gt;

&lt;p&gt;The problem? &lt;strong&gt;Speed&lt;/strong&gt;.&lt;br&gt;
Imagine a huge server with 1000+ routes. Then, to search for a specific route using this approach, what is the time required? &lt;strong&gt;O(n)&lt;/strong&gt;, &lt;code&gt;n&lt;/code&gt; being the &lt;code&gt;number of routes&lt;/code&gt;, i.e. 1000 here. That's a huge blow to the performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 The Better Approach
&lt;/h2&gt;

&lt;p&gt;You may be wondering, what should be done then? The answer lies in a magical little data structure, &lt;strong&gt;Trie&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;A trie is basically a tree, which stores strings character-by-character, branching out whenever required (see image for better understanding). This reduces unnecessary comparisons, and you can just follow the path in the trie and find the matching path.&lt;/p&gt;

&lt;p&gt;The time complexity? Just a mere &lt;strong&gt;O(s)&lt;/strong&gt;, &lt;code&gt;s&lt;/code&gt; being the &lt;code&gt;length of route&lt;/code&gt;. So, if "/users" is the URL, &lt;code&gt;s&lt;/code&gt; is 6. No matter how many thousands of routes exist in the server, this approach only thinks about the route that is being requested, significantly reducing the time taken and enhancing performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 The Even Better Approach
&lt;/h2&gt;

&lt;p&gt;Now, is there any way to make this approach even more performant? The answer is to &lt;strong&gt;use a HashMap&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The trie is still going to store every route as it used to store earlier, character-by-character. However, this seems inefficient too, as most routes that get requested to a server are usually just static sites ("/users", "/dashboard" etc).&lt;/p&gt;

&lt;p&gt;So, we use a hashmap here. While storing the routes, we get all the static parts (words) of the route (ex 'dashboard' and 'home' in "/home/dashboard") and store them in the hashmap as keys. Their values will store the ending node of the trie where these static words end.&lt;/p&gt;

&lt;p&gt;When a request comes in, we first check if each part is static or dynamic. If its static, we instantly look in the hashmap first. If found, we get at which node of the trie it ends, and start searching from there again.&lt;/p&gt;

&lt;p&gt;This updated approach helps in jumping through the static words stored in the trie and only check for dynamic parts (like 'id' in "/user/:id").&lt;/p&gt;

&lt;p&gt;Since most requested routes contain static routes, this approach improves performance significantly. Although the time complexity is still O(s) theoretically, in practice, most routes, especially ones with just static parts, get searched in just &lt;strong&gt;O(1)&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What's The Takeaway?
&lt;/h2&gt;

&lt;p&gt;Routing isn't just about matching URLs to functions—it directly impacts server performance.&lt;/p&gt;

&lt;p&gt;❌ A simple for loop works, but it doesn’t scale well.&lt;br&gt;
✅ A Trie speeds things up, as lookup time depends only on route length.&lt;br&gt;
🚀 Combining it with a HashMap makes it even more efficient, allowing many static routes to be matched in near O(1) time.&lt;/p&gt;

&lt;p&gt;Many modern frameworks use optimized routing techniques under the hood, but knowing how they work gives you the power to build faster, more scalable applications. So, the next time you write app.get("/user/:id") you'll know the real magic behind it 😉&lt;/p&gt;

&lt;p&gt;For more informative stuff, follow me on &lt;a href="https://www.linkedin.com/in/amartya-chowdhury" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://x.com/aether__flux" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>⚡ Tired of DB Setups? Meet Swapp: The Universal DB Adapter</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Sun, 09 Feb 2025 08:11:12 +0000</pubDate>
      <link>https://dev.to/aetherflux/tired-of-db-setups-meet-swapp-the-universal-db-adapter-105b</link>
      <guid>https://dev.to/aetherflux/tired-of-db-setups-meet-swapp-the-universal-db-adapter-105b</guid>
      <description>&lt;p&gt;Let's be honest: working with databases can be a pain. Whether its a SQL database like MySQL or PostgreSQL, or a NoSQL one like MongoDB, each has its own syntax, setup and quirks. Using any one of these involves copying and pasting tons of boilerplate code, and dealing with all sorts of dependencies.&lt;/p&gt;

&lt;p&gt;And don't even get me started on switching databases, especially from a SQL to a NoSQL one or vice-versa. Learning multiple different ways to write queries for the same basic operations gets annoying, right?&lt;/p&gt;

&lt;p&gt;That's where Swapp comes in!&lt;/p&gt;

&lt;p&gt;Imagine setting up a database with just one statement, and use one query language for both SQL and NoSQL databases. Sounds like a dream? Well, it just got real!&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Swapp.js is live!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aether-flux/swappjs" rel="noopener noreferrer"&gt;🔗 GitHub Repo&lt;/a&gt; | &lt;a href="https://www.npmjs.com/package/swapp.js" rel="noopener noreferrer"&gt;📦 NPM Package&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;🚀 Swapp.js just launched on &lt;a href="https://www.producthunt.com/posts/swapp-js" rel="noopener noreferrer"&gt;Product Hunt!&lt;/a&gt; and &lt;a href="https://peerlist.io/neobius/project/swappjs" rel="noopener noreferrer"&gt;Peerlist&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is Swapp?&lt;/li&gt;
&lt;li&gt;
How to use Swapp?

&lt;ul&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Configuring Your Database&lt;/li&gt;
&lt;li&gt;Basic CRUD Operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Why use Swapp?&lt;/li&gt;
&lt;li&gt;
Conclusion

&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What is Swapp?
&lt;/h2&gt;

&lt;p&gt;Swapp is an easy-to-use database abstraction layer for Node.js. It connects to both SQL (like Supabase) and NoSQL (like MongoDB) databases using a simple, unified interface. The beauty of Swapp is that it lets you use a universal query language - think SQL-like queries - across both SQL and NoSQL databases. No more changing the entirety of your code just to switch from a SQL to a NoSQL database (or the other way around).&lt;/p&gt;

&lt;p&gt;Here's what Swapp provides you with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Skip the tedious database setup process.&lt;/li&gt;
&lt;li&gt;Write queries in a SQL-like syntax that works across both MongoDB and Supabase (and more databases getting support soon).&lt;/li&gt;
&lt;li&gt;Focus on building your app, not on configuring your database.&lt;/li&gt;
&lt;li&gt;Enjoy easy-to-understand API calls for CRUD operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, it does the heavy-lifting so you don't have to. Just configure Swapp, and then you can start building your app's features immediately. Swapp will take care of setting up the database for you.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use Swapp?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Installing Swapp is really easy. Just download it from npm, and you're set to go!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install swapp.js --legacy-peer-deps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add swapp.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring Your Database
&lt;/h3&gt;

&lt;p&gt;Right now, Swapp supports MongoDB and Supabase. More databases are currently in development.&lt;/p&gt;

&lt;p&gt;If you're using MongoDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Swapp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;mongodb-connection-string&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;database-name&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you use Supabase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Swapp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supabase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;supabaseKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Supabase-Key&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Supabase-URL&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic CRUD Operations
&lt;/h3&gt;

&lt;p&gt;Most of the basic CRUD operations work just as expected. For example, to save data to the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;collection/table name&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now comes the fun part: the queries. Look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;collection/table name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WHERE name = "John"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This searches for entries in the database with name = "John". Classic SQL-like query. The catch? This works seamlessly, whether you're using a SQL database (like Supabase) or a NoSQL one (like MongoDB)!&lt;/p&gt;

&lt;p&gt;Similarly, there are functions for db.update() and db.delete() as well. Check out the GitHub repository of Swapp for more detailed documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Swapp?
&lt;/h2&gt;

&lt;p&gt;If you're still unsure why you should use Swapp when there are so many database packages out there, let me try changing your mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Save Time:&lt;/strong&gt; No more memorizing different query languages for different databases. Swapp lets you focus on building your app, instead of worrying about database setups and queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL and NoSQL in One Package:&lt;/strong&gt; Swapp gives you the flexibility to use both SQL and NoSQL databases. If you wanna try out MongoDB for some flexible data storage and then shift to Supabase for a more structured data, Swapp lets you do that easily by changing just a single statement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal for MVPs and Prototyping:&lt;/strong&gt; If you're building an MVP or a prototype and don't want to be bogged down by database setup, Swapps lets you just plug in and get started quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple, Intuitive API:&lt;/strong&gt; CRUD operations? Check. Universal queries? Check. But still easy to work with. You won't need to read through pages of documentation to get a simple query running.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Swapp is here to make your life easier. Whether you're new to databases or have been wrangling them for years, this tool can save you a ton of time and effort.&lt;/p&gt;

&lt;p&gt;So, why not give it a try? You'll be up and running in minutes, and you can spend your valuable time actually building your app.&lt;/p&gt;

&lt;p&gt;Check out the  &lt;a href="https://github.com/aether-flux/swappjs" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;  and leave a star if you found Swapp to be actually helpful in your development workflow. Feel free to leave any feedback and suggestions you may have, I am always open to new ideas.&lt;/p&gt;

&lt;p&gt;Let's swap out the complexity and start building!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create your own Event Scheduling API using Express and Supabase</title>
      <dc:creator>Amartya Chowdhury</dc:creator>
      <pubDate>Mon, 04 Nov 2024 15:51:54 +0000</pubDate>
      <link>https://dev.to/aetherflux/create-your-own-event-scheduling-api-using-express-and-supabase-2c40</link>
      <guid>https://dev.to/aetherflux/create-your-own-event-scheduling-api-using-express-and-supabase-2c40</guid>
      <description>&lt;p&gt;Ever needed a platform to manage your club's events? Or perhaps schedule meetings in your office? But in search of affordable platforms, you get lost in the numerous options presented to you? Or maybe you just want to organize your life better and schedule when you have to attend which events?&lt;/p&gt;

&lt;p&gt;Follow this post through the end, and you'll end up with a basic event scheduling API where all basic features like event creation and registration will be available.&lt;/p&gt;

&lt;p&gt;The GitHub repository for this project is at &lt;a href="https://github.com/xerctia/gatherly" rel="noopener noreferrer"&gt;https://github.com/xerctia/gatherly&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Express?
&lt;/h2&gt;

&lt;p&gt;Express is a Javascript framework for setting up and building servers to handle various kinds of requests like GET, POST etc. Express is one of the most popularly used backend frameworks, and is also one of the easiest framework for beginners to start with. In this blog, we will be using Express for making our server and setting up the required endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is PostgreSQL?
&lt;/h2&gt;

&lt;p&gt;PostgreSQL is an open-source relational database management system (RDBMS), known for its reliability, scalability, and support for complex queries. It offers advanced features like support for JSON data, full-text search, and extensibility, making it versatile for both small projects and large-scale applications. PostgreSQL is popular among developers and is valued for its robust performance.&lt;/p&gt;

&lt;p&gt;There are many PostgreSQL providers available on the web that allow usage of a PostgreSQL database, some free of cost and some with a paid plan. In this project, we will be using Supabase and its database as our PostgreSQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the project
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a folder for this project. I will name it Gatherly, which is the name I've decided.&lt;/li&gt;
&lt;li&gt;Set up Node and npm: &lt;code&gt;npm init -y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install Express and other required packages:
&lt;code&gt;npm install express dotenv cors pg&lt;/code&gt;
&lt;strong&gt;Note:&lt;/strong&gt; pg is the package used for using PostgreSQL in Node.js.&lt;/li&gt;
&lt;li&gt;Now create an &lt;code&gt;index.js&lt;/code&gt; file with the following boilerplate code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, Gatherly!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`server started on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congrats! You have successfully set up a basic server in Express!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Supabase with your Project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Supabase setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://supabase.com" rel="noopener noreferrer"&gt;https://supabase.com&lt;/a&gt; and log into or create an account, and then create a new project with any name you see fit. I have named it Gatherly (obviously).&lt;/li&gt;
&lt;li&gt;Now go to the project dashboard and then navigate to Project Settings -&amp;gt; Database.&lt;/li&gt;
&lt;li&gt;In the starting of the page, a section of "Connection String" will be present. Click the Node.js tab here and copy the connection string and store it somewhere for now.&lt;/li&gt;
&lt;li&gt;Now go to the SQL Editor and run the following query to create an 'events' table:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connecting database to Express
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to your project folder and create a file named &lt;code&gt;.env&lt;/code&gt;. Write &lt;code&gt;DATABASE_URL=&lt;/code&gt; and then paste the Connection String you copied earlier (Supabase setup: Step-3) and enclose it within double quotes. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL="postgresql://username:password@host:port/dbname"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create another JS file &lt;code&gt;db.js&lt;/code&gt; to set up and connect the PostgreSQL database.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rejectUnauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now lastly, we need to import this connected database to our main &lt;code&gt;index.js&lt;/code&gt; file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations, you have successfully connected your Supabase database to your index.js file. We are now ready to start building the actual API endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Endpoints
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GET /events : Fetch all events
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a new GET method as follows:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code to be written&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Inside this function, we will write the actual code that will fetch us the data. First of all, let's implement a try-catch block for better error handling.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code to be written&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database error.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This format will be maintained for all the endpoints we will be building. Within the try block, we will write the code for the required feature.&lt;/li&gt;
&lt;li&gt;To fetch all the events in the database, we need to query the database and store it in a variable. Since we are following an asynchronous approach, so we need to use await to store the data correctly.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The output of this query, i.e. result, has an array of objects called 'rows'. Here, we need to return all the events, so we will just return the entire 'rows'.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 200 = OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;With this, our first endpoint is ready! To test it out, you can go to the Table Editor at Supabase project's dashboard and add 2 or 3 events for testing purposes. The entire code for this endpoint is:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Getting all events&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 200 = OK&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  POST /events : Create a new event
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;First of all, let's set up a basic boilerplate of an endpoint:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// code to be written&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to create event.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this case, as we have some data we need from the user, we can define those outside of the try-catch block.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end_time&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;.....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now within the try block, we need to write the query to insert a row in a table. The query() method lets you denote variable values in the string query as $1, $2 etc. and then provide those variables in order in an array. This will be how we add our variable inputs from user to the query.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO events (title, description, start_time, end_time) VALUES ($1, $2, $3, $4) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Again, like the previous time, we will print the result rows. But this time, we only need to print the first element of the 'rows' array, which will be the row we just inserted.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// 201 = Resource Created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Hurray, we've built our endpoint to add new events! Here's the entire code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end_time&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Destructuring the input data&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Insert the event details into a new row in the table&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO events (title, description, start_time, end_time) VALUES ($1, $2, $3, $4) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// 201 = Resource Created&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to create event.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GET /event/:id : Fetch details of an individual event
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I'm sure you are clever enough to be able to set up a basic function for any endpoint, so I will not be showing that every time.&lt;/li&gt;
&lt;li&gt;Here, our goal is to create a dynamic endpoint, where the value of 'id' will keep changing. So, we've marked it as :id, and we can access its value as follows:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can also be done outside the try-catch, just like the input values in the previous endpoint.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now within the try block, we need to write the query for selecting rows where the 'id' field will be equal to the id provided. If there's no results found, that means the event with this id doesn't exist, so we can return a 404 error.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM events WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// event not found&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Event not found.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If this isn't the case, that means the event exists. But since 'rows' is an array, so even if it contains one element, we need to access it by rows[0]. So the required row is in rows[0].
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;And voila! You can now successfully get a specific event's details! Here's the full code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/event/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Destructuring the URL parameters&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get the current event row&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM events where id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// length 0 means no rows returned, i.e. event isn't found&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No event found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 404 = Resource Not Found&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// 200 = OK&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database error.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User Registration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Supabase
&lt;/h4&gt;

&lt;p&gt;For implementing this feature, you will need to create a new table in Supabase first.&lt;/p&gt;

&lt;p&gt;Go to SQL Editor and run the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;registrations&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event_id&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;specialty&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  POST /event/:id/register
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;We can take the input values as well as the parameter value outside the try-catch.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;specialty&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;.....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now we will first check whether the event with 'id' exists. For this, we will follow the approach of GET /event/:id, and check if rows.length is nonzero, i.e. it has some results.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM events WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Event not found.'});
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now that the event exists, we can write the query for actually adding a registration to the database to the new table we just created, i.e. 'registrations'.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO registrations (event_id, name, country, specialty) VALUES ($1, $2, $3, $4) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;specialty&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Registration successful!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Thus we have implemented a feature for registering users for an event as well! Here's the entire code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/event/:id/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Destructuring URL parameters&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;college&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;laptop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Destructuring input data&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Checking if event exists&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM events where id = $1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// length 0 means no rows returned, i.e. event isn't found&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Event not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 404 = Resource Not Found&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Insert new row for new registration&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO registrations (event_id, name, dept, college, country, laptop) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;college&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;laptop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Registration successful!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]});&lt;/span&gt; &lt;span class="c1"&gt;// 201 = Resource Created&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to register for event.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// 500 = Internal Server Error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GET /event/:id/registrations : Fetch all registrations for a given event
&lt;/h3&gt;

&lt;p&gt;This one is a homework for you guys. (Don't be mad, if you couldn't do it even after trying, the GitHub code is always available)&lt;br&gt;
A hint: You may check if the event exists in the same way as we did in POST /event/:id/register. After that, you need to write a SELECT query for registrations table to fetch all rows with the given event_id.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Similarly, you may also try and build an endpoint for deleting a particular event, like DELETE /event/:id .&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully created your own API for scheduling events and managing user registrations. You have come a long way.&lt;/p&gt;

&lt;p&gt;You can add more features, like adding a cron job so that events whose end_time have passed are deleted automatically.&lt;/p&gt;

&lt;p&gt;If you liked this post, drop a like, and comment if you have any doubts or just want to chat related to this. Also follow me on LinkedIn: &lt;a href="https://www.linkedin.com/in/amartya-chowdhury/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/amartya-chowdhury/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>postgres</category>
      <category>sql</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
