<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ByteChain]]></title><description><![CDATA[Software &amp; Blockchain Engineer | Technical Writer

Currently building fun apps and saas products to help developers

Building: roadflow-web.vercel.app &amp;]]></description><link>https://blog.covenlabs.space</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1743400682066/e5c12977-eed9-40b0-a77b-421ba94aa42e.png</url><title>ByteChain</title><link>https://blog.covenlabs.space</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 09:32:31 GMT</lastBuildDate><atom:link href="https://blog.covenlabs.space/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[React2Shell (CVE-2025-55182) Exploitation on AWS EC2 - A Real-World Incident Report]]></title><description><![CDATA[Executive Summary
On one of our AWS EC2 servers running a Next.js development environment, we discovered an active exploitation of the React2Shell vulnerability (CVE-2025-55182 / CVE-2025-66478). The attacker successfully installed cryptocurrency min...]]></description><link>https://blog.covenlabs.space/react2shell-cve-2025-55182-exploitation-on-aws-ec2-a-real-world-incident-report</link><guid isPermaLink="true">https://blog.covenlabs.space/react2shell-cve-2025-55182-exploitation-on-aws-ec2-a-real-world-incident-report</guid><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[CVE]]></category><category><![CDATA[exploit]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Thu, 15 Jan 2026 10:12:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768471770636/ff8ca12e-baa3-476e-8bf7-9126832acb08.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-executive-summary">Executive Summary</h2>
<p>On one of our AWS EC2 servers running a Next.js development environment, we discovered an active exploitation of the React2Shell vulnerability (CVE-2025-55182 / CVE-2025-66478). The attacker successfully installed cryptocurrency mining software with persistent cron jobs. This incident report details our discovery, response, and recommendations for the broader community.</p>
<h2 id="heading-incident-timeline-amp-discovery">Incident Timeline &amp; Discovery</h2>
<p>While investigating unusual server performance, we identified unauthorized mining activity connected to a Monero mining pool. Analysis revealed:</p>
<ul>
<li><p><strong>Mining Pool</strong>: MoneroOcean (moneroocean.stream)</p>
</li>
<li><p><strong>Attacker's Wallet Address</strong>: <code>42ZUiZsAoLeLjcaYK6rYQw1jyhadoB5kk5jXY5FJKoCkWzm964rqqBuGugSjqQZDB2B3JgE1YTGcHLEVN4nHNspH1UZX4nR</code></p>
</li>
<li><p><strong>Scope</strong>: 33+ active workers initially detected across multiple cloud providers (AWS, Azure, GCP)</p>
</li>
<li><p><strong>Current Status</strong>: Worker count has grown to 43+ as of this writing</p>
</li>
</ul>
<p>This indicates a widespread, ongoing campaign targeting vulnerable servers across multiple cloud platforms.</p>
<h2 id="heading-technical-background-the-react2shell-vulnerability">Technical Background: The React2Shell Vulnerability</h2>
<h3 id="heading-what-is-react2shell">What is React2Shell?</h3>
<p>React2Shell (CVE-2025-55182) is a critical remote code execution (RCE) vulnerability with a CVSS score of <strong>10.0</strong> - the maximum severity rating. It affects:</p>
<ul>
<li><p>React Server Components (RSC) in React 19.x</p>
</li>
<li><p>Next.js 15.x and 16.x using App Router</p>
</li>
<li><p>Next.js 14.3.0-canary.77 and later canary releases</p>
</li>
</ul>
<h3 id="heading-how-does-it-work">How Does It Work?</h3>
<p>The vulnerability stems from unsafe deserialization in the React Server Components "Flight" protocol. An attacker can:</p>
<ol>
<li><p>Send a single crafted HTTP POST request to any exposed Next.js App Router endpoint</p>
</li>
<li><p>Exploit the protocol's insecure handling of RSC payloads</p>
</li>
<li><p>Execute arbitrary code on the server with near-100% reliability</p>
</li>
<li><p>Establish persistence through cron jobs and backdoors</p>
</li>
</ol>
<p><strong>Critical Note</strong>: Default configurations are vulnerable - no code changes by developers are required for exploitation. A standard Next.js app created with <code>create-next-app</code> and built for production can be exploited immediately.</p>
<h2 id="heading-attack-vector-amp-exploitation">Attack Vector &amp; Exploitation</h2>
<h3 id="heading-what-we-observed">What We Observed</h3>
<p>The attacker leveraged CVE-2025-55182 to:</p>
<ol>
<li><p><strong>Initial Access</strong>: Exploited the vulnerable Next.js application endpoint</p>
</li>
<li><p><strong>Payload Delivery</strong>: Deployed cryptocurrency mining binaries</p>
</li>
<li><p><strong>Persistence</strong>: Created cron jobs to ensure the mining process always runs</p>
</li>
<li><p><strong>Evasion</strong>: Implemented mechanisms to restart the process if terminated</p>
</li>
<li><p><strong>Likely Backdoor</strong>: Given the sophistication, backdoors and additional access methods were likely established</p>
</li>
</ol>
<h3 id="heading-attempted-remediation-failures">Attempted Remediation Failures</h3>
<p>Our initial remediation attempts were unsuccessful:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Attempted process termination - FAILED</span>
<span class="hljs-built_in">kill</span> -9 &lt;mining_process_pid&gt;
<span class="hljs-comment"># Process automatically restarted</span>

<span class="hljs-comment"># Attempted cron job removal - FAILED  </span>
crontab -e  <span class="hljs-comment"># Removed malicious entries</span>
<span class="hljs-comment"># Miner continued running through alternative persistence mechanisms</span>

<span class="hljs-comment"># Attempted package updates - FAILED</span>
npm install next@latest
<span class="hljs-comment"># Downloads blocked/intercepted by attacker's modifications</span>
</code></pre>
<p>The attacker's persistence mechanisms and potential system-level access prevented clean remediation.</p>
<h2 id="heading-our-response-amp-recovery">Our Response &amp; Recovery</h2>
<h3 id="heading-decision-complete-server-replacement">Decision: Complete Server Replacement</h3>
<p>Given the severity and persistence of the compromise, we implemented a full server replacement strategy:</p>
<ol>
<li><p><strong>Provisioned New EC2 Instance</strong>: Launched a fresh instance with updated configurations</p>
</li>
<li><p><strong>Code Migration</strong>: Deployed application code to the new instance with patched dependencies</p>
</li>
<li><p><strong>Security Hardening</strong>: Implemented additional security controls before going live</p>
</li>
<li><p><strong>Old Instance Termination</strong>: Completely destroyed the compromised server</p>
</li>
</ol>
<h3 id="heading-why-full-replacement">Why Full Replacement?</h3>
<ul>
<li><p><strong>Unknown Compromise Depth</strong>: No way to guarantee removal of all backdoors</p>
</li>
<li><p><strong>Potential Credential Theft</strong>: SSH keys, environment variables, and secrets may have been exfiltrated</p>
</li>
<li><p><strong>Secondary Persistence</strong>: Attacker may have established multiple persistence mechanisms</p>
</li>
<li><p><strong>Cost-Benefit</strong>: Rebuilding was faster and more secure than forensic cleanup</p>
</li>
</ul>
<p><strong>Critical Consideration</strong>: Our server only hosted frontend applications with no databases or sensitive state. Had this contained databases, user data, or cryptographic keys, the impact would have been catastrophic.</p>
<h2 id="heading-recommended-actions-immediate">Recommended Actions - Immediate</h2>
<h3 id="heading-1-check-for-vulnerable-versions">1. Check for Vulnerable Versions</h3>
<p>Run the official scanner:</p>
<pre><code class="lang-bash">npx fix-react2shell-next
</code></pre>
<p>This will:</p>
<ul>
<li><p>Scan all <code>package.json</code> files (supports monorepos)</p>
</li>
<li><p>Identify vulnerable versions of React and Next.js</p>
</li>
<li><p>Recommend specific patched versions</p>
</li>
<li><p>Optionally apply fixes automatically</p>
</li>
</ul>
<h3 id="heading-2-verify-your-versions">2. Verify Your Versions</h3>
<p><strong>Vulnerable Versions:</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Framework</td><td>Vulnerable Versions</td><td>Patched Version</td></tr>
</thead>
<tbody>
<tr>
<td>Next.js</td><td>15.0.0 - 15.0.4</td><td>15.0.5</td></tr>
<tr>
<td>Next.js</td><td>15.1.0 - 15.1.8</td><td>15.1.9</td></tr>
<tr>
<td>Next.js</td><td>15.2.0 - 15.2.5</td><td>15.2.6</td></tr>
<tr>
<td>Next.js</td><td>15.3.0 - 15.3.5</td><td>15.3.6</td></tr>
<tr>
<td>Next.js</td><td>15.4.0 - 15.4.7</td><td>15.4.8</td></tr>
<tr>
<td>Next.js</td><td>15.5.0 - 15.5.6</td><td>15.5.7</td></tr>
<tr>
<td>Next.js</td><td>16.0.0 - 16.0.6</td><td>16.0.7</td></tr>
<tr>
<td>React</td><td>19.0 - 19.2</td><td>19.0.1, 19.1.2, 19.2.1</td></tr>
</tbody>
</table>
</div><h3 id="heading-3-patch-immediately">3. Patch Immediately</h3>
<p><strong>No workarounds exist</strong> - upgrading is the only solution:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># For Next.js</span>
npm install next@&lt;patched-version&gt;

<span class="hljs-comment"># For React (if using RSC directly)</span>
npm install react@19.0.1 react-dom@19.0.1
</code></pre>
<h3 id="heading-4-post-patch-actions">4. Post-Patch Actions</h3>
<p>After patching:</p>
<ul>
<li><p><strong>Rotate all secrets</strong>: API keys, database passwords, JWT secrets, etc.</p>
</li>
<li><p><strong>Review environment variables</strong>: Assume all credentials were compromised</p>
</li>
<li><p><strong>Audit SSH keys</strong>: Remove and regenerate all SSH access keys</p>
</li>
<li><p><strong>Check for persistence</strong>: Look for suspicious cron jobs, systemd services, startup scripts</p>
</li>
<li><p><strong>Monitor processes</strong>: Watch for unusual CPU usage or network activity</p>
</li>
<li><p><strong>Review access logs</strong>: Look for suspicious HTTP POST requests to RSC endpoints</p>
</li>
</ul>
<h3 id="heading-5-deploy-runtime-detection">5. Deploy Runtime Detection</h3>
<p>If using Falco or similar tools, deploy detection rules for React2Shell exploitation attempts.</p>
<h2 id="heading-signs-of-compromise">Signs of Compromise</h2>
<p>Check your servers for these indicators:</p>
<h3 id="heading-process-level-indicators">Process-Level Indicators</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Unusual CPU usage</span>
top
htop

<span class="hljs-comment"># Suspicious processes</span>
ps aux | grep -E <span class="hljs-string">"(xmrig|monero|miner|cpuminer)"</span>

<span class="hljs-comment"># Network connections to mining pools</span>
netstat -tulpn | grep -E <span class="hljs-string">"(moneroocean|pool\.|stratum)"</span>
</code></pre>
<h3 id="heading-persistence-mechanisms">Persistence Mechanisms</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Check cron jobs</span>
crontab -l
cat /etc/crontab
ls -la /etc/cron.*

<span class="hljs-comment"># Check systemd services</span>
systemctl list-units --<span class="hljs-built_in">type</span>=service --state=running

<span class="hljs-comment"># Check startup scripts</span>
cat /etc/rc.local
ls -la /etc/init.d/
</code></pre>
<h3 id="heading-file-system-artifacts">File System Artifacts</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># Look for recently modified files</span>
find / -mtime -7 -<span class="hljs-built_in">type</span> f 2&gt;/dev/null

<span class="hljs-comment"># Check for hidden files in common directories</span>
ls -la /tmp
ls -la /var/tmp
ls -la ~/.config
</code></pre>
<h2 id="heading-industry-impact-amp-statistics">Industry Impact &amp; Statistics</h2>
<p>Based on security research:</p>
<ul>
<li><p><strong>39% of cloud environments</strong> contain Next.js or React in vulnerable versions</p>
</li>
<li><p><strong>61% of environments</strong> with Next.js have publicly accessible instances</p>
</li>
<li><p><strong>44% of all cloud environments</strong> have publicly exposed Next.js (regardless of version)</p>
</li>
<li><p>Exploitation observed across AWS, Azure, GCP, and other cloud platforms</p>
</li>
<li><p>Public RCE exploits available with near-100% reliability</p>
</li>
</ul>
<h2 id="heading-references-amp-additional-resources">References &amp; Additional Resources</h2>
<h3 id="heading-official-advisories">Official Advisories</h3>
<ul>
<li><p><a target="_blank" href="https://nextjs.org/blog/CVE-2025-66478">Next.js Security Advisory (CVE-2025-66478)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/blog/2025/12/03/react-security-update">React Security Advisory (CVE-2025-55182)</a></p>
</li>
<li><p><a target="_blank" href="https://aws.amazon.com/security/security-bulletins/AWS-2025-030/">AWS Security Bulletin AWS-2025-030</a></p>
</li>
</ul>
<h3 id="heading-security-research">Security Research</h3>
<ul>
<li><p><a target="_blank" href="https://www.wiz.io/blog/critical-vulnerability-in-react-cve-2025-55182">Wiz Research: React2Shell Analysis</a></p>
</li>
<li><p><a target="_blank" href="https://www.microsoft.com/en-us/security/blog/2025/12/15/defending-against-the-cve-2025-55182-react2shell-vulnerability-in-react-server-components/">Microsoft Security Blog: Defending Against React2Shell</a></p>
</li>
<li><p><a target="_blank" href="https://unit42.paloaltonetworks.com/cve-2025-55182-react-and-cve-2025-66478-next/">Palo Alto Unit 42: Exploitation Report</a></p>
</li>
</ul>
<h3 id="heading-tools">Tools</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/vercel-labs/fix-react2shell-next">Official Fix Tool</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/assetnote/react2shell-scanner">Assetnote Scanner</a></p>
</li>
</ul>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ol>
<li><p><strong>Patch immediately</strong> - This is a maximum severity (10.0) RCE with active exploitation</p>
</li>
<li><p><strong>Assume compromise</strong> - If you're running vulnerable versions publicly, assume you've been targeted</p>
</li>
<li><p><strong>Full rotation</strong> - Rotate all secrets, keys, and credentials after patching</p>
</li>
<li><p><strong>Consider full rebuild</strong> - For critical systems, rebuilding may be safer than remediation</p>
</li>
<li><p><strong>Monitor actively</strong> - Watch for signs of cryptocurrency mining or unusual activity</p>
</li>
<li><p><strong>Stay informed</strong> - Follow security advisories for additional related vulnerabilities</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The React2Shell vulnerability represents a critical threat to the React and Next.js ecosystem. The ease of exploitation, combined with the widespread adoption of these frameworks, has created an attractive target for threat actors.</p>
<p>Our incident demonstrates that attackers are actively exploiting this vulnerability at scale, targeting cloud infrastructure across multiple providers. The sophistication of the persistence mechanisms we encountered suggests organized threat actors, not just opportunistic attacks.</p>
<p><strong>Do not delay patching.</strong> Every hour your vulnerable Next.js application remains exposed is an opportunity for compromise. The attacker we encountered has already compromised 40+ servers - don't let yours be next.</p>
<hr />
<p><em>Have you encountered React2Shell exploitation? Share your experience in the comments or reach out to contribute to community awareness.</em></p>
<p><strong>Update your servers. Rotate your secrets. Stay vigilant.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Unlocking the Web using HTTPS Outcalls on ICP]]></title><description><![CDATA[The world of blockchain and smart contracts has long been hampered by the limitations of operating in a closed, self-contained environment. Traditional blockchain networks have struggled to connect their on-chain applications and logic to the wealth ...]]></description><link>https://blog.covenlabs.space/unlocking-the-web-using-https-outcalls-on-icp</link><guid isPermaLink="true">https://blog.covenlabs.space/unlocking-the-web-using-https-outcalls-on-icp</guid><category><![CDATA[icp]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[Ethereum]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Thu, 07 Nov 2024 17:56:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731002096968/2ce4c4e1-7656-4613-861e-0fc4e5428410.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The world of blockchain and smart contracts has long been hampered by the limitations of operating in a closed, self-contained environment. Traditional blockchain networks have struggled to connect their on-chain applications and logic to the wealth of data and services available on the open web. This disconnect has been a significant barrier to the wider adoption and utility of smart contract-powered decentralized applications (dApps).</p>
<p>The emergence of the "<strong>oracle problem</strong>" has been a central challenge in bridging the gap between the blockchain and the broader digital landscape. Developers have relied on centralized Oracle services to fetch off-chain data and integrate it into their smart contracts, but this approach has introduced new trust assumptions, vulnerabilities, and operational complexities.</p>
<p><img src="https://lh5.googleusercontent.com/c8tBiHAEX8IWTgVVeWOlTm1_D3fZphzicq6t0Fog7cJvagwZyVd37cZFnbECO2MNAQW5amnDP5ZEiGS6jhVvqXQ-k3_QHrsyjGcIulGKtjQGt0J-rgbDAqzE3GXnpxHLvvpbmxWP-KSOsWWtORN9Kwo" alt="Disconnection of open web and blockchains. Source: https://hacken.io/discover/blockchain-oracles/" /></p>
<h2 id="heading-the-oracle-problem">The Oracle Problem</h2>
<p>This problem arises from the fundamental nature of blockchain technology. Smart contracts, by design, can receive messages and update their internal state, but they cannot directly send messages or interact with external systems that are not native to them. This means that it’s easy for a solidity contract to communicate with another solidity contract, but much more harder and complicated to make an api call to a rest API.</p>
<p>This one-way communication model means that smart contracts are largely isolated from the wealth of data and services available on the open web, which is predominantly hosted on traditional, centralized Web2 platforms. What a limitation right?</p>
<h3 id="heading-oracles-a-solution-or-a-new-problem">Oracles → a solution or a new problem?</h3>
<p>To overcome this limitation, developers have turned to Oracle services – centralized entities that act as intermediaries, fetching data from external sources and relaying it to smart contracts. While oracles have enabled some level of integration between blockchains and the broader digital ecosystem, they come with their own set of drawbacks.</p>
<h4 id="heading-trust-assumptions">Trust Assumptions</h4>
<p>Oracles introduce additional trust assumptions, as users must trust the Oracle provider to faithfully retrieve and deliver the requested data. But this goes against the foundational structure of blockchains. Blockchains must aim to be fully trustless.</p>
<h4 id="heading-spof">SPOF</h4>
<p>They also create potential single points of failure, as the Oracle service itself can become a vulnerability if compromised or disrupted.</p>
<h2 id="heading-https-outcalls">HTTPS Outcalls</h2>
<p>The Internet Computer, a revolutionary blockchain platform developed by DFINITY, has introduced a game-changing solution to the oracle problem – HTTPS outcalls. This feature allows smart contracts, known as "canisters" on the Internet Computer, to directly make HTTPS requests to external data sources and services, effectively bridging the gap between the blockchain and the broader Web2 world.</p>
<p>Under the hood, HTTPS outcalls work by placing the HTTP request in the subnet's replicated state. Each replica of the Internet Computer then independently makes the same request and reaches a consensus on the response, which is then delivered back to the originating canister. This approach ensures that the integrity of the data is maintained, as the decentralized network of replicas verifies the response, eliminating the need for a centralized Oracle service.</p>
<p>This approach solves two major problems created by oracles, which are:</p>
<ol>
<li><p><strong>Trust Assumptions:</strong> Now developers no longer need to trust a centralized service to be honest and not manipulate data responses.</p>
</li>
<li><p><strong>SPOF:</strong> HTTP requests are executed by decentralized replicas on the Internet Computer and need to reach a consensus state before the response is returned. If a replica is down or unreachable, the canister will still work.</p>
</li>
</ol>
<h3 id="heading-use-cases-for-https-outcalls">Use Cases for HTTPS Outcalls</h3>
<p>The ability to make direct HTTPS outcalls from smart contracts opens up a vast array of new use cases for blockchain-powered applications. Some key examples include:</p>
<ol>
<li><p>Retrieving real-time market data: Canisters can directly fetch cryptocurrency exchange rates, stock prices, and other financial data from Web2 APIs, enabling the development of decentralized finance (DeFi) applications that can accurately track and respond to market fluctuations. An example live on ICP is the Exchange Rate canister - <a target="_blank" href="https://internetcomputer.org/docs/current/developer-docs/defi/exchange-rate-canister">https://internetcomputer.org/docs/current/developer-docs/defi/exchange-rate-canister</a>.</p>
</li>
<li><p>Integrating with other blockchains and Web2 services: HTTPS outcalls allow for seamless integration between the Internet Computer and other blockchain networks, as well as traditional Web2 services, enabling cross-chain communication and the development of interoperable dApps.</p>
</li>
<li><p>Sending notifications and communications: Canisters can use HTTPS outcalls to trigger external actions, such as sending emails, SMS messages, or push notifications, enhancing the user experience and enabling new use cases for decentralized applications.</p>
</li>
<li><p>Accessing IoT data, weather forecasts, sports scores, and more: The possibilities for HTTPS outcalls extend far beyond financial data, as canisters can directly retrieve a wide range of information from various Web2 sources, unlocking new opportunities for innovative dApps.</p>
</li>
</ol>
<h3 id="heading-success-stories">Success Stories</h3>
<h4 id="heading-a-exchange-rate-canister-xrchttpsinternetcomputerorgdocscurrentdeveloper-docsdefiexchange-rate-canister">A. <a target="_blank" href="https://internetcomputer.org/docs/current/developer-docs/defi/exchange-rate-canister">Exchange Rate Canister (XRC)</a></h4>
<p>To demonstrate the power of HTTPS outcalls, the DFINITY team has developed the Exchange Rate Canister (XRC) – a smart contract that fetches real-time cryptocurrency exchange rates directly from major exchanges, without the need for any centralized oracle services.</p>
<p>The XRC canister leverages HTTPS outcalls to query public APIs offered by leading cryptocurrency exchanges, such as Coinbase and Binance, to retrieve the latest prices for a variety of digital assets. It can then provide this data to other canisters, enabling the development of decentralized exchange (DEX) applications and other DeFi tools that require accurate and up-to-date market information.</p>
<p>By eliminating the reliance on oracles, the XRC demonstrates how HTTPS outcalls can simplify the integration of blockchain-based applications with the broader digital ecosystem, paving the way for greater innovation and adoption in the Web3 space.</p>
<p><a target="_blank" href="https://kzwfs-haaaa-aaaak-ak3uq-cai.icp0.io/"><strong>B. PatriotAI Canister</strong></a></p>
<p>PatriotAI extensively used HTTPS outcalls to send prompts to OpenAI Assistant API and query run status periodically on a canister. It was able to offer personalized experiences to users of the learning platform by utilizing a generative AI provider, OpenAI, to generate questions to test learners on their progress through course modules.</p>
<p>By eliminating the need for oracles, PatriotAI can provide its users with a trustless and readily available environment to learn and train themselves about corruption.</p>
<h3 id="heading-the-impact-of-https-outcalls">The Impact of HTTPS Outcalls</h3>
<p>The introduction of HTTPS outcalls on the Internet Computer has the potential to revolutionize the way blockchain-based applications interact with the wider digital landscape. By removing the need for centralized oracle services, HTTPS outcalls eliminate the associated trust assumptions, vulnerabilities, and operational complexities, allowing developers to focus on building innovative and reliable decentralized applications.</p>
<p>This paradigm shift unlocks a wealth of new use cases for smart contracts, as they can now directly access a vast array of data and services available on the open web. From DeFi applications that leverage real-time market data to dApps that seamlessly integrate with other blockchains and Web2 services, the possibilities are vast and exciting.</p>
<p>As more developers explore and leverage the power of HTTPS outcalls, we can expect to see a surge of innovation and adoption in the Web3 space. By bridging the gap between blockchain and the broader digital world, HTTPS outcalls have the potential to accelerate the path towards true blockchain singularity, where the majority of computations and interactions occur on decentralized platforms.</p>
<h2 id="heading-takeaway">Takeaway</h2>
<p>The introduction of HTTPS outcalls on the Internet Computer blockchain represents a significant breakthrough in the ongoing quest to integrate blockchain technology with the wider digital ecosystem. By allowing smart contracts to directly fetch data and interact with external services, this feature overcomes the limitations of traditional oracle-based approaches and opens up a world of new possibilities for decentralized applications.</p>
<p>As developers continue to explore and harness the power of HTTPS outcalls, we can expect to see a surge of innovation in the Web3 space, with applications that seamlessly bridge the gap between blockchain and the broader digital landscape. This technology has the potential to catalyze the widespread adoption of decentralized solutions, paving the way for a future where the majority of our digital interactions and computations occur on secure, transparent, and autonomous blockchain networks.</p>
]]></content:encoded></item><item><title><![CDATA[What Exactly Is Neo's Built-In Oracle Service]]></title><description><![CDATA[Imagine you're planning a picnic with friends. You've checked the weather forecast, packed your basket, and are all set for a sunny day out. But what if there was a way to guarantee compensation if the weather unexpectedly turned sour? Enter the worl...]]></description><link>https://blog.covenlabs.space/what-exactly-is-neos-built-in-oracle-service</link><guid isPermaLink="true">https://blog.covenlabs.space/what-exactly-is-neos-built-in-oracle-service</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Ethereum]]></category><category><![CDATA[neo]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Bitcoin]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Mon, 23 Sep 2024 22:07:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727129171926/75b83dd1-57b8-49a2-91ea-67ed21acfc84.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you're planning a picnic with friends. You've checked the weather forecast, packed your basket, and are all set for a sunny day out. But what if there was a way to guarantee compensation if the weather unexpectedly turned sour? Enter the world of blockchain technology and Neo's built-in oracle service – a fascinating realm where digital contracts can interact with real-world data to create innovative solutions for everyday problems.</p>
<p>If you're new to the world of crypto and web3, don't worry! We're about to embark on a journey that will demystify these concepts and show you how they're shaping our future. So, grab a cup of your favorite beverage, and let's dive into the exciting world of Neo and its oracle service.</p>
<h2 id="heading-what-is-neo">What is Neo?</h2>
<p>Before we delve into oracles, let's start with the basics. <strong>Neo is a blockchain platform</strong> – think of it as a digital ledger that records transactions in a secure, transparent, and unchangeable way. But Neo isn't just any blockchain; it's often called the "Chinese Ethereum" because of its ability to host smart contracts.</p>
<p>Now, smart contracts are like digital vending machines. You put in a coin (or in this case, cryptocurrency), and if certain conditions are met, you get your snack (or the desired outcome of the contract). These contracts can automatically execute actions when specific conditions are fulfilled, without the need for intermediaries.</p>
<p>What makes Neo special is its focus on creating a "Smart Economy." It aims to digitize real-world assets and automate their management through smart contracts. And this is where oracles come into play.</p>
<h2 id="heading-understanding-oracles">Understanding Oracles</h2>
<p>Imagine blockchain as a super-secure, windowless room where all these smart contracts live. They're great at processing information within their own world, but they have no idea what's happening outside. This is where oracles come in – they're like trustworthy messengers that bring real-world information into the blockchain world.</p>
<p>Oracles are crucial because they allow smart contracts to interact with data from the outside world. Without oracles, smart contracts would be limited to working with information already stored on the blockchain. But with oracles, the possibilities become endless!</p>
<h2 id="heading-neos-built-in-oracle-service">Neo's Built-In Oracle Service</h2>
<p>Now, here's where Neo shines. Many blockchain platforms require developers to use third-party oracle services, which can be complex and costly. But Neo? Neo has a built-in oracle service that comes as part of its core functionality. It's like having a Swiss Army knife when others are carrying a single-blade pocket knife.</p>
<p>Neo's oracle service works by allowing node operators (think of them as the maintainers of the blockchain network) to act as oracle providers. These providers fetch external data and bring it onto the blockchain in a secure and verifiable manner. This data can then be used by smart contracts to execute actions based on real-world events.</p>
<h2 id="heading-real-world-use-cases">Real-World Use Cases</h2>
<p>Now, let's explore some exciting ways Neo's oracle service can be used in the real world:</p>
<ol>
<li><p><strong>Weather-based Insurance</strong>: Remember our picnic scenario? With Neo's oracle service, you could create an insurance policy that automatically pays out if it rains on your planned picnic day. The smart contract would use weather data provided by the oracle to determine if it should release the funds.</p>
</li>
<li><p><strong>Supply Chain Management</strong>: Imagine a smart contract that tracks the temperature of a shipment of vaccines. The oracle could provide real-time temperature data from IoT sensors. If the temperature goes above or below the safe range, the contract could automatically notify the relevant parties or even reroute the shipment.</p>
</li>
<li><p><strong>Decentralized Sports Betting</strong>: Sports enthusiasts could place bets using smart contracts that automatically pay out based on the final scores of games. The oracle would provide verified sports results, ensuring fair and transparent betting.</p>
</li>
<li><p><strong>Real Estate Tokenization</strong>: Property values could be updated in real-time based on market data provided by oracles. This would allow for more accurate and dynamic pricing of tokenized real estate assets.</p>
</li>
</ol>
<h2 id="heading-benefits-of-neos-oracle-service">Benefits of Neo's Oracle Service</h2>
<p>Neo's built-in oracle service offers several advantages:</p>
<ul>
<li><p><strong>Reliability</strong>: Since it's built into the core protocol, it's as reliable as the Neo blockchain itself.</p>
</li>
<li><p><strong>Cost-effectiveness</strong>: Developers don't need to pay for or integrate third-party services, reducing costs and complexity.</p>
</li>
<li><p><strong>Ease of Use</strong>: The service is readily available and easy to implement, lowering the barrier to entry for developers.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we've seen, Neo's built-in oracle service is a powerful tool that bridges the gap between the digital world of blockchain and our physical reality. It opens up a world of possibilities, from weather-based insurance to supply chain management and beyond.</p>
<p>The future potential of this technology is immense. As more real-world data becomes available to smart contracts, we could see innovations in fields ranging from healthcare to finance, from environmental protection to governance.</p>
<p>So, the next time you hear about blockchain or crypto, remember – it's not just about digital currencies. It's about creating a smarter, more connected world where digital contracts can interact with our physical reality in meaningful ways.</p>
<p>Are you excited about the possibilities? Why not dive deeper into the Neo ecosystem? Explore their documentation, join their community, or even try building your own oracle-powered application. The future is here, and it's more accessible than you might think!</p>
]]></content:encoded></item><item><title><![CDATA[Demystifying Neo's Developer Ecosystem]]></title><description><![CDATA[In the ever-evolving landscape of blockchain technology, one platform stands out for its developer-friendly approach and innovative features: Neo. If you're new to the world of cryptocurrencies and blockchain, fear not! This article will guide you th...]]></description><link>https://blog.covenlabs.space/demystifying-neos-developer-ecosystem</link><guid isPermaLink="true">https://blog.covenlabs.space/demystifying-neos-developer-ecosystem</guid><category><![CDATA[neo3]]></category><category><![CDATA[C#]]></category><category><![CDATA[Python]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[golang]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[neo]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Developer]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[dapps]]></category><category><![CDATA[dapps development]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Thu, 19 Sep 2024 22:25:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726784554577/63d34cc3-8dd6-49b2-8662-0fce6fbc7b3b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the ever-evolving landscape of blockchain technology, one platform stands out for its developer-friendly approach and innovative features: Neo. If you're new to the world of cryptocurrencies and blockchain, fear not! This article will guide you through Neo's rich developer ecosystem, breaking down complex concepts into digestible bits. So, let's embark on this journey together, exploring the tools, resources, and opportunities that Neo offers to developers of all skill levels.</p>
<h2 id="heading-the-power-of-neo">The Power of Neo</h2>
<p>Imagine a world where digital assets, smart contracts, and decentralized applications (dApps) coexist seamlessly, powered by a blockchain that's both efficient and developer-friendly. This is the vision that Neo, often called the "Chinese Ethereum," is bringing to life.</p>
<p>But why should you, as a budding developer or curious enthusiast, care about Neo's ecosystem? The answer lies in the growing importance of blockchain technology and the concept of Web3 - the next evolution of the internet. As we move towards a more decentralized digital world, platforms like Neo are paving the way for innovative applications that could reshape industries and empower users in unprecedented ways.</p>
<h2 id="heading-what-is-neo-blockchain-simplified">What is Neo? Blockchain Simplified</h2>
<p>Before we dive into the developer tools, let's take a moment to understand what Neo is all about. At its core, Neo is a blockchain platform - think of it as a digital ledger that records transactions and data in a secure, transparent, and immutable way. But Neo isn't just any blockchain; it's designed with developers in mind.</p>
<p>What sets Neo apart? Imagine a Swiss Army knife for blockchain development. Neo offers:</p>
<ol>
<li><p>Support for multiple programming languages (we'll get to that later)</p>
</li>
<li><p>A dual-token system (NEO for governance and GAS for transaction fees)</p>
</li>
<li><p>A unique consensus mechanism called delegated Byzantine Fault Tolerance (dBFT)</p>
</li>
</ol>
<p>These features make Neo not just powerful, but also accessible to developers from various backgrounds.</p>
<h2 id="heading-web3-and-neo-a-match-made-in-digital-heaven">Web3 and Neo: A Match Made in Digital Heaven</h2>
<p>You've probably heard the term "Web3" buzzing around, but what does it really mean? Think of the internet's evolution:</p>
<ul>
<li><p>Web1: The read-only web (static websites)</p>
</li>
<li><p>Web2: The read-write web (social media, user-generated content)</p>
</li>
<li><p>Web3: The read-write-own web (decentralized, user-controlled data and assets)</p>
</li>
</ul>
<p>Web3 is all about giving power back to users, enabling them to own their data, digital assets, and online identities. This is where Neo shines. By providing a platform for building decentralized applications, Neo is helping to bring the Web3 vision to life.</p>
<p>Imagine creating an application where users truly own their in-game items or a social media platform where users control their data. These are the kinds of possibilities that Neo opens up in the Web3 world.</p>
<h2 id="heading-neos-developer-toolbox-your-gateway-to-blockchain">Neo's Developer Toolbox: Your Gateway to Blockchain</h2>
<p>Now that we've laid the groundwork, let's explore the tools that make Neo a developer's playground. Think of these as your trusty companions on your blockchain development journey:</p>
<h3 id="heading-neo-cli-your-command-center">Neo-CLI: Your Command Center</h3>
<p><a target="_blank" href="https://developers.neo.org/docs/n3/node/cli/setup">Neo-CLI</a> is like the command prompt for Neo. It's a powerful tool that allows developers to interact with the Neo blockchain directly. Whether you're deploying smart contracts, managing wallets, or syncing with the network, Neo-CLI has got you covered.</p>
<h3 id="heading-neo-gui-the-friendly-face-of-blockchain">Neo-GUI: The Friendly Face of Blockchain</h3>
<p>For those who prefer a more visual approach, <a target="_blank" href="https://developers.neo.org/docs/n3/node/gui/install">Neo-GUI</a> offers a graphical interface to interact with the Neo blockchain. It's perfect for beginners who want to explore Neo's capabilities without diving into command-line operations.</p>
<p><img src="https://developers.neo.org/assets/images/guinetwork-8d6adeff138013ab3c4998fffc111f7b.png" alt /></p>
<h3 id="heading-neo-express-your-blockchain-playground">Neo-Express: Your Blockchain Playground</h3>
<p>Imagine having your own private Neo blockchain to experiment with. That's exactly what <a target="_blank" href="https://github.com/neo-project/neo-express">Neo-Express</a> offers. It's a rapid deployment tool that allows developers to set up a private Neo blockchain instance for testing and development. Think of it as your sandbox where you can build and break things without consequences.</p>
<h4 id="heading-features">Features</h4>
<ul>
<li><p>Blockchain instance management</p>
</li>
<li><p>Wallet management</p>
</li>
<li><p>Asset management</p>
</li>
<li><p>Smart contract management</p>
</li>
<li><p>Blockchain checkpoint and rollback</p>
</li>
</ul>
<h2 id="heading-smart-contracts-the-building-blocks-of-blockchain-applications">Smart Contracts: The Building Blocks of Blockchain Applications</h2>
<p>Smart contracts are at the heart of blockchain applications. But what exactly are they? Imagine a vending machine. You put in a coin, press a button, and out comes your snack. Smart contracts work similarly but in the digital realm. They're self-executing contracts with the terms directly written into code.</p>
<p>What makes Neo's approach to smart contracts special is its support for multiple programming languages. While many blockchain platforms require learning a specific language, Neo allows developers to write smart contracts in languages they might already know, such as C#, Python, or Java.</p>
<p>NeoContract, Neo's smart contract system, is designed to be developer-friendly and efficient. It supports features like deterministic finite automata for enhanced performance and a manifest for better security.</p>
<p>To make development even more accessible, Neo offers frameworks tailored to different programming languages:</p>
<h3 id="heading-neo-blockchain-toolkit-your-all-in-one-development-suitehttpsmarketplacevisualstudiocomitemsitemnamengd-seattleneo-blockchain-toolkit"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ngd-seattle.neo-blockchain-toolkit">Neo Blockchain Toolkit: Your All-in-One Development Suite</a></h3>
<h4 id="heading-c-python-go">C#, Python, Go</h4>
<p>Imagine having a Swiss Army knife for Neo development - that's exactly what the Neo Blockchain Toolkit (NBT) is. Seamlessly integrated with <strong>Visual Studio Code</strong>, the most popular code editor, NBT is a one-stop shop for creating and preparing smart contracts for production.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726784047686/4fb0c26a-482e-481d-bad8-6d2e91283db8.png" alt class="image--center mx-auto" /></p>
<p>Key features of NBT include:</p>
<ul>
<li><p>Easy deployment of private networks</p>
</li>
<li><p>Compilation, deployment, and invocation of smart contracts</p>
</li>
<li><p>Fully integrated debugging experience</p>
</li>
<li><p>Time-travel debug support</p>
</li>
<li><p>Source-mapped opcode view</p>
</li>
<li><p>Automated test harness</p>
</li>
</ul>
<p>Whether you're a seasoned blockchain developer or just starting out, NBT provides a best-in-class development experience that streamlines your workflow and boosts productivity.</p>
<h3 id="heading-neoonehttpsneo-oneio"><a target="_blank" href="https://neo-one.io/">NEO•ONE</a></h3>
<h4 id="heading-typescript-javascript">TypeScript, JavaScript</h4>
<p>If TypeScript or JavaScript is your language of choice, NEO•ONE has got you covered. This end-to-end development framework for Neo applications includes:</p>
<ul>
<li><p>Tools for local network setup</p>
</li>
<li><p>Contract compiling and deploying</p>
</li>
<li><p>Wallet handling</p>
</li>
<li><p>Automated testing</p>
</li>
<li><p>Client APIs to simplify interaction with deployed contracts</p>
</li>
</ul>
<p>NEO•ONE empowers web developers to leverage their existing skills to build blockchain applications, bridging the gap between web and blockchain development.</p>
<h3 id="heading-neogohttpsgithubcomnspcc-devneo-go-gos-gateway-to-neo-smart-contracts"><a target="_blank" href="https://github.com/nspcc-dev/neo-go">NeoGo</a>: Go's Gateway to Neo Smart Contracts</h3>
<h4 id="heading-golang">Golang</h4>
<p>Developed by Neo SPCC, NeoGo is more than just a compiler - it's a fully-featured alternative implementation of the core Neo stack, written in Go. For Go developers looking to step into the world of blockchain, NeoGo offers:</p>
<ul>
<li><p>A highly performant node implementation</p>
</li>
<li><p>A compiler for Go smart contracts</p>
</li>
<li><p>An SDK for app integration</p>
</li>
</ul>
<p>NeoGo is well-documented and provides a smooth onramp for Go developers to start building on Neo. Whether you're creating smart contracts or building full-scale decentralized applications, NeoGo equips you with the tools you need to leverage the power of Go in the Neo ecosystem.</p>
<h3 id="heading-neo-devpack-dotnethttpsgithubcomneo-projectneo-devpack-dotnet-c-contracts-made-easy"><a target="_blank" href="https://github.com/neo-project/neo-devpack-dotnet/">Neo-devpack-dotnet</a>: C# Contracts Made Easy</h3>
<h4 id="heading-c">C</h4>
<p>For the C# developers out there, the Neo Project offers Neo-devpack-dotnet. This core devpack provides all the tools required to compile smart contracts written in C#. Key features include:</p>
<ul>
<li><p>Production of deployable NEF contract files</p>
</li>
<li><p>Generation of manifest files</p>
</li>
<li><p>Emission of debug information in a standard format for use with the Neo Debugger</p>
</li>
</ul>
<p>The familiarity of C# combined with the power of Neo makes this an attractive option for .NET developers venturing into blockchain development.</p>
<h3 id="heading-boahttpsgithubcomcityofzionneo3-boa-python-slithers-onto-the-blockchain"><a target="_blank" href="https://github.com/CityOfZion/neo3-boa">Boa</a>: Python Slithers onto the Blockchain</h3>
<h4 id="heading-python">Python</h4>
<p>Python developers, meet Boa - your bridge to Neo smart contract development. Developed by COZ, Boa is designed to feel as natural as possible for Python programmers. Features include:</p>
<ul>
<li><p>Decorator-assisted contract development</p>
</li>
<li><p>Helper functions for common blockchain operations</p>
</li>
<li><p>Type hints for improved code clarity</p>
</li>
<li><p>Support for testing against the core VM TestEngine</p>
</li>
<li><p>Generation of standard format debug data for use with the Neo Blockchain Toolkit</p>
</li>
</ul>
<p>With Boa, you can bring Python's simplicity and readability to your blockchain projects, making smart contract development more accessible than ever.</p>
<h3 id="heading-neow3j-compilerhttpsgithubcomneow3jneow3-java-joins-the-blockchain-party"><a target="_blank" href="https://github.com/neow3j/neow3">Neow3j Compiler</a>: Java Joins the Blockchain Party</h3>
<h4 id="heading-java-kotlin">Java, Kotlin</h4>
<p>For those more comfortable in the Java world, AxLabs brings you the Neow3j Compiler. As one of the three main components of the Neow3j library, this compiler turns Java contracts into the NEF and manifest files required for deployment on N3 networks. Key features include:</p>
<ul>
<li><p>A Gradle plugin to aid compilation</p>
</li>
<li><p>Automatic generation of standard debugging information</p>
</li>
<li><p>Seamless integration with the broader Neow3j ecosystem</p>
</li>
</ul>
<p>The Neow3j Compiler allows Java and Kotlin developers to leverage their existing skills and the robust Java ecosystem in blockchain development.</p>
<h2 id="heading-neos-software-development-kits-sdks-your-language-your-choice">Neo's Software Development Kits (SDKs): Your Language, Your Choice</h2>
<p>One of Neo's greatest strengths is its commitment to language diversity, perfectly exemplified by its range of Software Development Kits (SDKs). These SDKs are like specialized toolboxes, each designed for a specific programming language, enabling developers to interact with the Neo blockchain using their preferred language.</p>
<h3 id="heading-overview-of-neo-sdks">Overview of Neo SDKs</h3>
<p>Neo provides SDKs for a variety of popular programming languages. This multilingual approach is part of Neo's strategy to lower the entry barrier for blockchain development. Let's explore the key SDKs in the Neo ecosystem:</p>
<h3 id="heading-neo-rpc-sdkhttpsdevelopersneoorgdocsn3developtoolsdkcontract-cs-bridge-to-neo"><a target="_blank" href="https://developers.neo.org/docs/n3/develop/tool/sdk/contract">Neo RPC SDK</a>: C#'s Bridge to Neo</h3>
<h4 id="heading-c-1">C</h4>
<p>Developed by The Neo Project, the Neo RPC SDK is a dependency library that streamlines the integration of C# applications with Neo. It's well-suited for a variety of projects, including:</p>
<ul>
<li><p>Games</p>
</li>
<li><p>Wallets</p>
</li>
<li><p>Other blockchain-integrated applications</p>
</li>
</ul>
<p>Key features of the Neo RPC SDK include:</p>
<ul>
<li><p>Easy construction of transactions</p>
</li>
<li><p>Simplified invocation of RPC interfaces</p>
</li>
<li><p>Straightforward calling of deployed contracts</p>
</li>
</ul>
<p>For C# developers looking to bring their applications into the blockchain world, the Neo RPC SDK provides a familiar and powerful toolkit.</p>
<h3 id="heading-neon-jshttpsdojocozioneo3neon-js-javascripts-gateway-to-neo"><a target="_blank" href="https://dojo.coz.io/neo3/neon-js/">Neon-js</a>: JavaScript's Gateway to Neo</h3>
<h4 id="heading-javascript-typescript">JavaScript, TypeScript</h4>
<p>For JavaScript developers, COZ offers Neon-js, a lightweight library for Neo blockchain interaction. Designed for both backend and frontend use, Neon-js is versatile and powerful. Its key features include:</p>
<ul>
<li><p>RPC interaction</p>
</li>
<li><p>Wallet manipulation</p>
</li>
<li><p>Contract invocation</p>
</li>
</ul>
<p>The NetworkFacade class in Neon-js provides a quick way to bootstrap developers, making it easy to construct interactions with the Neo blockchain. Whether you're building a web application or a Node.js backend, Neon-js equips you with the tools you need.</p>
<h3 id="heading-mambahttpsgithubcomcityofzionneo-mamba-pythons-path-to-neo-blockchain"><a target="_blank" href="https://github.com/CityOfZion/neo-mamba">Mamba</a>: Python's Path to Neo Blockchain</h3>
<h4 id="heading-python-1">Python</h4>
<p>Mamba, also developed by COZ, is the main entry point for Python developers wishing to interact with the Neo blockchain. This comprehensive SDK includes:</p>
<ul>
<li><p>Packages for network connectivity</p>
</li>
<li><p>Data storage utilities</p>
</li>
<li><p>Cryptography tools</p>
</li>
<li><p>Handling of complex data types specific to N3</p>
</li>
<li><p>Smart contract execution capabilities</p>
</li>
<li><p>Basic node functionality</p>
</li>
</ul>
<p>Mamba brings the simplicity and readability of Python to Neo blockchain development, making it easier than ever for Python developers to create blockchain-integrated applications.</p>
<h3 id="heading-neo-gogogohttpsgithubcomneo-ngdneo3-gogogo-gos-toolkit-for-neo"><a target="_blank" href="https://github.com/neo-ngd/neo3-gogogo">Neo-gogogo</a>: Go's Toolkit for Neo</h3>
<h4 id="heading-golang-1">Golang</h4>
<p>For the Go enthusiasts, Neo Global Development offers Neo-gogogo, a lightweight Go SDK. This comprehensive toolkit provides all the structures and methods required to interface with the Neo blockchain. With Neo-gogogo, you can:</p>
<ul>
<li><p>Manage wallets</p>
</li>
<li><p>Verify state proofs</p>
</li>
<li><p>Interact with contracts and tokens</p>
</li>
<li><p>Build transactions</p>
</li>
<li><p>Send RPC requests</p>
</li>
<li><p>And much more</p>
</li>
</ul>
<p>Neo-gogogo makes it easy for Go developers to build any kind of application on the Neo blockchain, from simple scripts to complex decentralized applications.</p>
<h3 id="heading-neofs-api-sdks-interfacing-with-decentralized-storage">NeoFS API SDKs: Interfacing with Decentralized Storage</h3>
<h4 id="heading-golang-c">Golang, C</h4>
<p>Neo SPCC provides SDKs for interfacing with NeoFS, Neo's decentralized storage system:</p>
<ol>
<li><p><a target="_blank" href="https://github.com/nspcc-dev/neofs-api-go">NeoFS API Go</a>: This SDK implements all the core NeoFS components needed to help applications integrate with NeoFS via its Protobuf-based API. It's perfect for Go developers looking to incorporate decentralized storage into their applications.</p>
</li>
<li><p><a target="_blank" href="https://github.com/neo-ngd/neofs-api-csharp">NeoFS API CSharp</a>: For C# developers, this SDK provides similar functionality, allowing .NET applications to interact seamlessly with NeoFS.</p>
</li>
</ol>
<p>These SDKs open up possibilities for creating applications that leverage both blockchain technology and decentralized storage.</p>
<h3 id="heading-why-sdks-matter">Why SDKs Matter</h3>
<p>The importance of these SDKs in the Neo ecosystem cannot be overstated. They serve several crucial functions:</p>
<ol>
<li><p>Lower Entry Barrier: Developers can start building on Neo using languages they already know.</p>
</li>
<li><p>Faster Development: SDKs provide pre-built functions and utilities, saving developers from reinventing the wheel.</p>
</li>
<li><p>Best Practices: SDKs often incorporate best practices for interacting with the blockchain, helping developers create more secure and efficient applications.</p>
</li>
<li><p>Community Growth: By supporting multiple languages, Neo encourages a diverse developer community, fostering innovation and collaboration.</p>
</li>
</ol>
<h3 id="heading-choosing-your-sdk">Choosing Your SDK</h3>
<p>When deciding which SDK to use, consider your existing skills and the requirements of your project. Are you building a web application? Neon-js might be your best bet. Working on a data-heavy application in Python? Mamba could be the way to go. Building a Go microservice? Neo-gogogo has got you covered.</p>
<p>Remember, regardless of which SDK you choose, you're tapping into the same powerful Neo blockchain. It's just a matter of which language you're most comfortable speaking.</p>
<p>As you embark on your Neo development journey, take some time to explore these SDKs. Try out a few examples, build some small projects, and see which one feels right for you. After all, the best tool is the one you enjoy using.</p>
<h2 id="heading-the-neo-community-your-support-system">The Neo Community: Your Support System</h2>
<p>No developer is an island, and in the Neo ecosystem, you're part of a vibrant community. Here's how you can tap into this wealth of knowledge and support:</p>
<ul>
<li><p><a target="_blank" href="https://neo.org/dev">Official Documentation</a>: Neo's documentation is comprehensive and regularly updated, serving as your go-to resource for all things Neo.</p>
</li>
<li><p>Community Forums: Platforms like Neo's <a target="_blank" href="https://www.reddit.com/r/NEO/">subreddit</a> and Discord channel are bustling with developers sharing ideas, solving problems, and discussing the latest in Neo development.</p>
</li>
<li><p>Social Media: Follow Neo on <a target="_blank" href="https://x.com/Neo_Blockchain">Twitter</a> and join their <a target="_blank" href="https://t.me/NEO_EN">Telegram</a> group to stay updated on the latest news and events.</p>
</li>
<li><p><a target="_blank" href="https://neo.org/blog/details/4315">NeoPod ambassador program</a></p>
</li>
</ul>
<p>Remember, every expert was once a beginner. Don't hesitate to ask questions and engage with the community - you'll find a supportive group eager to help you grow.</p>
<h2 id="heading-dapps-in-the-neo-ecosystemhttpsndapporg-inspiration-for-your-next-project"><a target="_blank" href="https://ndapp.org/"><strong>DApps in the Neo Ecosystem</strong></a>: Inspiration for Your Next Project</h2>
<p>To give you an idea of what's possible with Neo, let's take a quick look at some notable decentralized applications in the ecosystem:</p>
<ul>
<li><p><a target="_blank" href="https://neo.link/">NEO Name Service</a>: Think of it as a blockchain-based domain name system, making crypto addresses more human-readable.</p>
</li>
<li><p><a target="_blank" href="https://flamingo.finance/">Flamingo Finance</a>: A suite of interoperable protocols for decentralized finance (DeFi) on Neo.</p>
</li>
<li><p><a target="_blank" href="https://ghostmarket.io/">GhostMarket</a>: An NFT marketplace built on Neo, showcasing the platform's capabilities in handling digital assets.</p>
</li>
</ul>
<p>These dApps demonstrate the versatility of Neo and might spark ideas for your blockchain projects.</p>
<h2 id="heading-your-neo-adventure-awaits">Your Neo Adventure Awaits</h2>
<p>As we wrap up our exploration of Neo's developer ecosystem, I hope you're feeling inspired and empowered to dive into this exciting world of blockchain development. Neo's commitment to developer-friendliness, combined with its powerful features and vibrant community, makes it an excellent platform for both beginners and experienced developers alike.</p>
<p>Whether you're dreaming of creating the next big DeFi application, a revolutionary NFT marketplace, or something entirely new that the world hasn't seen yet, Neo provides the tools and support to turn your vision into reality.</p>
<p>Remember, the world of blockchain and Web3 is still in its early stages. By starting your journey with Neo today, you're positioning yourself at the forefront of a technological revolution. Who knows? The next groundbreaking dApp could be the one you create.</p>
<p>So, fire up your development environment, join the Neo community, and start building. Your adventure in the world of blockchain development begins now. Welcome to the future of the internet - <strong>welcome to Neo</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726783615073/33e007c2-c2bc-47ea-8062-af4430cd3848.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Demystifying Internet Infrastructure: A Comprehensive Guide for Software Engineers]]></title><description><![CDATA[This has been an age-old question. A good understanding of what happens here can make employers think highly of you because it shows you know what you do. The answer to this question varies depending on what area of tech you are focused on. Say you a...]]></description><link>https://blog.covenlabs.space/demystifying-internet-infrastructure-a-comprehensive-guide-for-software-engineers</link><guid isPermaLink="true">https://blog.covenlabs.space/demystifying-internet-infrastructure-a-comprehensive-guide-for-software-engineers</guid><category><![CDATA[webserver]]></category><category><![CDATA[Databases]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[System Design]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Mon, 16 Oct 2023 03:58:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428225000/b8a4e7fe-a945-418c-bfee-dd3c92726d2e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This has been an age-old question. A good understanding of what happens here can make employers think highly of you because it shows you know what you do. The answer to this question varies depending on what area of tech you are focused on. Say you are a frontend engineer, this question requires you to talk more about the DOM rendering. If you are a SRE, this question requires you to talk more about how load balancing works.</p>
<p>This article covers how a software engineer can answer this question. If this is your first time hearing about DNS, this is going to be a great ride.</p>
<h2 id="heading-dns-lookup">DNS Lookup</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428370902/0142d6a6-3ec8-4095-be3f-99c99f5f464b.png" alt class="image--center mx-auto" /></p>
<p>Firstly, What is DNS? Domain Name System is a large distributed phonebook that maps domain names to IP addresses. Humans access information online through domain names, such as <a target="_blank" href="http://nytimes.com">nytimes.com</a> or <a target="_blank" href="http://espn.com">espn.com</a>. DNS translates the domain names to IP addresses so browsers can load Internet resources.</p>
<p>When you enter <code>google.com</code> in the browser, let's take Chrome for example. It checks its DNS cache if it exists. If it doesn't it uses the OS DNS service to resolve the domain IP address. If the DNS service can't find it in the cache and host file, then it requests the DNS server configured on the network stack.</p>
<h2 id="heading-tcpip">TCP/IP</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428456315/1829fe4c-9574-490a-a037-1dd6f0d0f876.png" alt class="image--center mx-auto" /></p>
<p>When the browser gets the IP address of the domain name, it uses the IP and port number, which defaults to 80 for HTTP connection and 443 for HTTPS connection, to make a TLS handshake with the web server. This creates a connection session between the browser and the web server for other HTTP requests.</p>
<p>When making this connection the browser using the OS network stack, crafts an IP packet containing the connection message, how the packet will get to the server, and how the server response can get back to the browser.</p>
<h2 id="heading-firewal">Firewal</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428542363/5ae1cbc6-1e9d-44f9-8539-392d7d161570.png" alt class="image--center mx-auto" /></p>
<p>A firewall is a network security software that monitors incoming and outgoing network traffic and decides whether to allow or block specific traffic based on a defined set of security rules.</p>
<p>The network packet sent from the browser needs to pass the server firewall check before it can get to the web server for a connection handshake. If the packet doesn't pass the firewall inspection the traffic is rejected, else approved.</p>
<p>Firewalls typically work on the network layer, the transport layer. However, some are also capable of working as high as the application layer, Layer 7.</p>
<h2 id="heading-httpsssl">HTTPS/SSL</h2>
<p>If the connection to be created requires an HTTPS connection, the browser uses port 443 and ensures the packet sent is encrypted. Secure Sockets Layer (SSL) certificates, sometimes called digital certificates, are used to establish an encrypted connection between a browser or user’s computer and a server or website.</p>
<p>You can use the lock icon in Chrome search bar to inspect if the browser established a secure connection with the server. You can also see the certificate authority that provided the Digital certificates to the server.</p>
<p>The encrypted connection helps secure data transmitted over the internet. It helps the server verify that HTTP responses were sent by the real server it is connected to. Also ensure that no other person on the internet can inspect the data transmitted, helping users log in or card information stay secure.</p>
<h2 id="heading-load-balancer">Load-balancer</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428573555/c6ab9f11-fd25-416b-b6d0-fffc09c02629.png" alt class="image--center mx-auto" /></p>
<p>Let's say the web server is getting too many HTTP requests due to an increasing user base or user activity. One solution is to increase the overall capacity of the server housing the web server, this is known as vertical scaling. But this is not the best solution as it's very expensive and requires heavy migration if it's needed to move the web server data to a new server. A solution most web service providers go for is vertical scaling. Instead of increasing the capability of a single server, they create more servers.</p>
<p>This brings up a new problem, how will the browser locate the web server to connect to? That's where and why a load balancer comes into place. It ensures requests from the internet pass through a single point and then distributes requests to its servers according to its algorithm.</p>
<p>Some load balancers can be configured to direct requests to certain servers depending on the HTTP request. Load balances can be used on different network layers. Layer 7 load balancers route network traffic in a much more sophisticated way than Layer 4 load balancers, particularly applicable to TCP‑based traffic such as HTTP. A Layer 7 load balancer terminates the network traffic and reads the message within.</p>
<h2 id="heading-web-server">Web server</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697428605103/425767af-146e-4b17-9ba1-402e90724618.png" alt class="image--center mx-auto" /></p>
<p>Web servers deliver static content, like HTML pages, images, videos, and files. Examples of web servers are Apache and Nginx. It uses the HTTP request to load the static content to send back as an HTTP response. This response is what is later rendered to you in the browser. <code>google.com</code> css, js, and images which are sent back to your browser and are then displayed for you to see and use.</p>
<p>Web servers play a very important role in this whole process, they are the main entity that serves most web content. Static files could have also been configured with CDNs to serve static content faster to you based on your location.</p>
<h2 id="heading-application-server">Application server</h2>
<p>This is closely related to web servers but serves dynamic content instead. Dynamic content means you might not get the same content as someone living far away from your country or continent. Let's take for example google recognizes a popular holiday in your location, the content you will get will be different from another person in another country that does not celebrate that holiday.</p>
<p>Application servers are also widely used on the internet today to give users personalized experiences when using the internet. It's closely related to the idea of having sessions, where a user is identified by a fixed data like IP address or Authentication data.</p>
<p>Application servers execute programs deployed for them. They send the HTTP requests to these programs which then decide on what HTTP response to send back to the application server. This decision could vary on different data, an example is why Google might use your IP or GPS location to serve you something unique.</p>
<h2 id="heading-database">Database</h2>
<p>A database is an organized collection of structured information, or data, typically stored electronically in a computer system. Programs executed by the application server might require a connection to a database to get information related to HTTP requests. This allows for persistent dynamic content.</p>
<p>From the example used earlier, the information regarding the holidays of several countries and the content to be displayed stay in a database, making it persistent and easily accessible by the program.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, understanding the intricate workings of the internet's infrastructure, from DNS lookups to load balancing, and the critical components that power it, such as web servers, application servers, and databases, is paramount for any software engineer. This knowledge not only showcases a deep understanding of the technological ecosystem but also demonstrates a level of expertise that can earn respect and trust from employers.</p>
<p>DNS, the backbone of the internet, translates human-readable domain names into IP addresses, allowing us to access online resources effortlessly. The journey from a user's query to the actual web server involves several crucial steps, each with its significance.</p>
<p>TCP/IP and firewalls play essential roles in establishing secure connections and ensuring data integrity. The use of HTTPS/SSL certificates further enhances security and privacy for users, safeguarding their data from potential threats.</p>
<p>In the face of increasing user demands, load balancers come to the rescue by efficiently distributing traffic across multiple servers, ensuring a smooth and responsive user experience. This scaling strategy is not only cost-effective but also minimizes the need for complex server migrations.</p>
<p>Web servers deliver static content, while application servers provide dynamic, personalized experiences for users. These elements, along with databases, form the foundation of modern web applications, enabling the persistent storage and retrieval of information.</p>
<p>In a world where digital interactions have become a fundamental part of our lives, comprehending the intricate web of technology that underlies it all is not only a valuable skill but a testament to a software engineer's prowess in shaping the digital landscape. With this knowledge, engineers can create robust, secure, and efficient systems that drive the Internet forward, making it a safer and more dynamic environment for all its users.</p>
]]></content:encoded></item><item><title><![CDATA[Building and Testing C Projects with GitHub Actions]]></title><description><![CDATA[Continuous Integration and Deployment / Development, CI/CD, is becoming more popular recently. Developers that have little knowledge of CI/CD now stand to have an upper hand at job interviews. Because most companies now use CI/CD automation to stream...]]></description><link>https://blog.covenlabs.space/building-and-testing-c-projects-with-github-actions</link><guid isPermaLink="true">https://blog.covenlabs.space/building-and-testing-c-projects-with-github-actions</guid><category><![CDATA[Git]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[C]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sun, 13 Aug 2023 20:18:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691957062158/c3036e5d-850c-45f6-9d30-5f4d1687a278.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuous Integration and Deployment / Development, CI/CD, is becoming more popular recently. Developers that have little knowledge of CI/CD now stand to have an upper hand at job interviews. Because most companies now use CI/CD automation to streamline their product testing and save time.</p>
<p>CI/CD is automating what developers already do. For example, running regression tests, and deploying new features. It’s important because it saves time and eliminates the possibility of human errors. Have you ever experienced forgetting to add an env key when deploying that new feature that depends on a new secret key? These kinds of little mistakes might cost users' trust.</p>
<p>You can also use CI/CD to automate your code testing. No need to run tests manually for every single commit to the repository. You can run automation for tests using tools like GitHub Actions, and Jenkins.</p>
<p>This article covers how you can use GitHub action to automate tests and builds in your C projects.</p>
<blockquote>
<p>You can use GitHub Actions to automate many development workflows. This article covers how to use it with C programming language by explaining the basics of GitHub Actions. If you understand the basics you will be able to use it for other projects written in different programming languages or frameworks.</p>
</blockquote>
<h2 id="heading-prerequisites">Prerequisites 💻</h2>
<p>To follow this article, you need to have;</p>
<ol>
<li><p>an understanding of writing C,</p>
</li>
<li><p>an understanding of how to build C programs with GCC,</p>
</li>
<li><p>gcc installed on your machine, and</p>
</li>
<li><p>a little understanding of Git and GitHub.</p>
</li>
</ol>
<h2 id="heading-project-setup">Project Setup 🤓</h2>
<p>You need to have a codebase with tests first before automating its testing. There is a simple C codebase already provided. You can clone it to get started, but to work with GitHub Actions you need to fork the repository. This is because you need permission to trigger workflow runs on a particular repository. By forking the repository you have access to trigger workflow runs on the forked repository. This is needed so you can visualize and test your workflow runs. The next section covers what is called a <strong>workflow</strong>.</p>
<p>Repository to fork: <a target="_blank" href="https://github.com/devvspaces/dsa-with-c">https://github.com/devvspaces/dsa-with-c</a></p>
<p>Description: This is a repository that implements many data structures and algorithms in C and includes tests.</p>
<p>This repository already has GitHub Actions workflow configured for testing. You need to delete the <code>.github</code> folder in the root directory to start afresh.</p>
<h2 id="heading-what-is-github-action">What Is GitHub Action? 🤔</h2>
<p>GitHub Actions helps you to automate your development workflows.</p>
<blockquote>
<p>GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want. - GitHub Actions documentation</p>
</blockquote>
<p>GitHub actions can be used to automate many software workflows. A single automation flow from start to end is called a workflow run in GitHub Actions. Developers can configure multiple workflows, each for separate tasks like regression testing and deployment. Each workflow can have one or more jobs.</p>
<p><strong>Workflows</strong> can be configured to be triggered by an event in your GitHub repository. For example, you can have one workflow to build and test when there is a new pull request. Then another workflow to deploy your application every time you push a new commit. Also, another workflow to add a label every time someone opens a new issue.</p>
<p><strong>Events</strong> are specific operations that trigger a workflow run. Events can be a new pull request or a new build release. You can configure workflows to listen to only events originating from specific branches or tags.</p>
<p><strong>Jobs</strong> in a workflow are a group of steps executed on the same runner. A step can be a script or an action. For example, there can be a step for building a C source code and another step for executing the build.</p>
<p><strong>Actions</strong> are a complex set of steps that are often repeated. For example, checking out a repository on a runner. Actions are reusable in many workflows and repositories. A developer does not need to rewrite the steps for checking out a repository on a runner, there are already efficient actions for this.</p>
<p><strong>Runners</strong> are servers that execute jobs in a workflow when it’s triggered. A runner can only run a single job at a time. GitHub offers Ubuntu Linux, Microsoft Windows, and macOS runners to run your workflows. Each workflow run executes in a fresh, newly-provisioned virtual machine.</p>
<h2 id="heading-setting-up-your-workflow">Setting Up Your Workflow 💻</h2>
<p>To create a new workflow in your repository you need to create a <code>.github/workflows</code> directory in your root directory. Then create a new file called <code>ctest.yml</code>. The file name is at your discretion but it must have a .yml extension. This file will contain configurations to build and test the source code in the repository.</p>
<p><code>name</code> specifies the name of a workflow file.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># ctest.yml</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">C</span> <span class="hljs-string">Build</span> <span class="hljs-string">Test</span>
</code></pre>
<p>The <code>on</code> key configures events and resources that trigger workflow runs.</p>
<p>The code below configures a workflow run when there is a push or pull request to the master branch.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># ctest.yml</span>
<span class="hljs-string">...</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">"master"</span> ]
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">"master"</span> ]
</code></pre>
<p>To specify each job and its respective steps, you can use the job's key and steps key for each job. This is where most configurations exist. Steps like checking out your repository on a runner and executing scripts or commands are here.</p>
<p><code>jobs</code> groups together all the jobs that run in a workflow.</p>
<p><code>build-and-execute</code> defines this job's name. The child keys define the properties of this job. This job handles building and executing the code because it’s faster and each job runs on its runner. Meaning, jobs can’t access each other’s files.</p>
<p><code>runs-on</code> configures the job to run on the latest version of an Ubuntu Linux runner.</p>
<p><code>steps</code> groups together all the steps that run in the build-and-execute job. Each item nested under this section is a separate action or shell script.</p>
<p><code>uses</code> specifies this step to run v3 of the actions/checkout action. This action checks out your repository onto the runner, allowing you to run scripts or other actions against your code (such as build and test tools). You should use the checkout action any time your workflow will use the repository's code.</p>
<p>The run keyword instructs this step to execute a command on the runner. In this case, gcc compiles and build all the c files in the project to an executable called <code>dsa</code>. Then the next step executes this executable. The last step deletes the build from the runner, but this step is not required. The runner deletes all the files created in the runner when each job is complete.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># ctest.yml</span>
<span class="hljs-string">...</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-execute:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">source</span> <span class="hljs-string">code</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">gcc</span> <span class="hljs-string">-Wall</span> <span class="hljs-string">-Werror</span> <span class="hljs-string">-Wextra</span> <span class="hljs-string">-pedantic</span> <span class="hljs-string">-std=gnu89</span> <span class="hljs-string">*/*.c</span> <span class="hljs-string">*/*/*.c</span> <span class="hljs-string">*/*/*/*.c</span> <span class="hljs-string">-o</span> <span class="hljs-string">dsa</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">./dsa</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clean</span> <span class="hljs-string">build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">rm</span> <span class="hljs-string">-f</span> <span class="hljs-string">dsa</span>
</code></pre>
<p>Your complete workflow file should now look like this.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># ctest.yml</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">C</span> <span class="hljs-string">Build</span> <span class="hljs-string">Test</span>

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

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-execute:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">source</span> <span class="hljs-string">code</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">gcc</span> <span class="hljs-string">-Wall</span> <span class="hljs-string">-Werror</span> <span class="hljs-string">-Wextra</span> <span class="hljs-string">-pedantic</span> <span class="hljs-string">-std=gnu89</span> <span class="hljs-string">*/*.c</span> <span class="hljs-string">*/*/*.c</span> <span class="hljs-string">*/*/*/*.c</span> <span class="hljs-string">-o</span> <span class="hljs-string">dsa</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">./dsa</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clean</span> <span class="hljs-string">build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">rm</span> <span class="hljs-string">-f</span> <span class="hljs-string">dsa</span>
</code></pre>
<p>Now you can commit and push.</p>
<p><strong>Visualizing Your Workflow Run 📈</strong></p>
<p>To visualize your new workflow run. Head over to your repository on GitHub. Under your repository name, click the actions tab. There you will see the new workflow run triggered by the push event you initiated.</p>
<p><img src="https://docs.github.com/assets/cb-21779/images/help/repository/actions-tab.png" alt="Screenshot of the tabs for the github/docs repository. The &quot;Actions&quot; tab is highlighted with an orange outline." /></p>
<p>From the list of workflow runs, click the name of the run to see the workflow run summary. In the left sidebar, you will the list of jobs in execution for the workflow. Click the job you want to see. In this case that will be the build-and-execute job. To view the results of a step, click the step. All standard output you will get on a normal machine is available under each step in the job.</p>
<h2 id="heading-conclusion">Conclusion 👋</h2>
<p>Hope you now understand how GitHub Actions work and how to configure a simple workflow. It’s easy to use GitHub Actions to automate workflows for many programming languages and frameworks.</p>
<p>You can always check the <a target="_blank" href="https://docs.github.com/en/actions/">documentation</a> for more understanding of writing complex workflows. It’s recommended to check out popular open-source frameworks to learn more about using GitHub Actions.</p>
<h2 id="heading-resources">Resources</h2>
<p><a target="_blank" href="https://docs.github.com/en/actions/">GitHub Actions Documentation</a></p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/training/modules/introduction-to-github-actions/">Microsoft Github Actions Course</a></p>
<p><a target="_blank" href="https://dev.to/devvspaces/mastering-django-cicd-using-github-actions-2912">Using Github Actions with Django</a></p>
]]></content:encoded></item><item><title><![CDATA[Streamlining Big Number Calculations in C using GMP]]></title><description><![CDATA[Nowadays, technologies like Cryptography need computers to compute complex mathematical operations. These algorithms need the CPU to perform arithmetic operations on large numbers with high precision.
The amount of data a processor can execute at onc...]]></description><link>https://blog.covenlabs.space/streamlining-big-number-calculations-in-c-using-gmp</link><guid isPermaLink="true">https://blog.covenlabs.space/streamlining-big-number-calculations-in-c-using-gmp</guid><category><![CDATA[C]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[DEVCommunity]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Cryptography]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sat, 29 Jul 2023 11:14:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690629125561/b81bd346-6710-4d20-9d5e-a67b4cb8eebf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nowadays, technologies like Cryptography need computers to compute complex mathematical operations. These algorithms need the CPU to perform arithmetic operations on large numbers with high precision.</p>
<p>The amount of data a processor can execute at once depends on its number of virtual memory addresses. The maximum integer representation a 32-bit processor can work with is 4,294,967,295 (2^32 − 1), while for a 64-bit processor is 18,446,744,073,709,551,615 (2^64 − 1). These bit constraints affect C standard integer and float data types.</p>
<p>Most high-level languages, like Python, allows programmers to work with larger numbers. Allowing programmers to write programs for processing numbers larger than what the CPU can handle. It's possible to write programs for calculating big numbers in C, but it can get very complex and confusing.</p>
<p>GMP, GNU Multiple Precision Arithmetic Library, streamlines the complexity of working with big numbers in C. This article covers how you can use the GMP Library to perform basic mathematical operations on various kinds of numbers.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow this article, you need to have;</p>
<ul>
<li><p>A basic understanding of C,</p>
</li>
<li><p>GCC installed - for compiling C programs,</p>
</li>
<li><p>Basic understanding of GCC,</p>
</li>
<li><p>Access to the internet - for installing GMP, and</p>
</li>
<li><p>A text editor was installed.</p>
</li>
</ul>
<h2 id="heading-what-is-gmp">What is GMP?</h2>
<p>GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating-point numbers. There is no practical limit to the precision except the ones implied by the available memory in the machine GMP runs on. GMP has a rich set of functions, and the functions have a regular interface. - <a target="_blank" href="http://gmplib.org">gmplib.org</a></p>
<p>GMP allows you to calculate big numbers of many kinds with high precision. It represents numbers in its program as strings.</p>
<h2 id="heading-installing-gmp">Installing GMP</h2>
<p>To install the GMP library, you can follow this informative guide. It explains how you can download, configure and build the library on Windows, Mac, and Linux.</p>
<h2 id="heading-performing-arithmetical-operations-using-gmp">Performing Arithmetical Operations Using GMP</h2>
<p>After installing the library, you need to include the GMP header file in your program to use the library for calculations.</p>
<h3 id="heading-addition">Addition</h3>
<p>For adding two integers, you need to declare and initialize the variables in a special way before calculations.</p>
<p>Include GMP library header. This allows you to access the types and macros declared in the header file.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;gmp.h&gt;</span></span>
</code></pre>
<p>Declare and initialize the variables for the result, and the numbers to add together.</p>
<pre><code class="lang-c"><span class="hljs-keyword">mpz_t</span> res, num_a, num_b;

<span class="hljs-comment">/* Initializing integers */</span>
mpz_init(res), mpz_init(num_a), mpz_init(num_b);
</code></pre>
<p>Initializing the variables using <code>mpz_init</code> function tells GMP to allocate memory space to the variables. Then you can assign any large number to the initialized variables.</p>
<p>The lines below assign <code>3479349783486297692763769376273723897236</code> to <code>num_a</code> and <code>9223372036854775807</code> to <code>num_b</code>. There is no limit to the amount of precision you get when using GMP for calculations.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Assigning integers */</span>
mpz_set_str(num_a, <span class="hljs-string">"3479349783486297692763769376273723897236"</span>, <span class="hljs-number">10</span>);
mpz_set_str(num_b, <span class="hljs-string">"9223372036854775807"</span>, <span class="hljs-number">10</span>);
</code></pre>
<p>The <code>mpz_set_str</code> function takes the first argument as the variable to assign a value. The second argument is the string representation of the integer you want to assign. The third argument represents the base of the integer (which, in this case, is the second argument). In the above example, the integers are in base 10, meaning decimal numbers.</p>
<p>Now you can add the number together using the <code>mpz_add</code> function from the GMP library. The function sets <code>res</code> to <code>num_a + num_b</code>. Then you can use <code>gmp_printf</code> to print the values. It works like C standard library printf function. The only difference is that <code>gmp_printf</code> allows you to format larger numbers. The <code>%Zd</code> flag in the format string in <code>gmp_printf</code> is to format large integers.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Addition */</span>
mpz_add(res, num_a, num_b);
gmp_printf(<span class="hljs-string">"Addition:\n%Zd + %Zd = %Zd\n\n"</span>, num_a, num_b, res);
</code></pre>
<p>Now you need to clear the variables. Clearing the variables frees the memory allocated for the variables.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Clearing memory */</span>
mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);
</code></pre>
<p>The full program should look like this.</p>
<pre><code class="lang-c"><span class="hljs-comment">// main.c</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;gmp.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    <span class="hljs-keyword">mpz_t</span> res, num_a, num_b;

    <span class="hljs-comment">/* Initializing integers */</span>
    mpz_init(res), mpz_init(num_a), mpz_init(num_b);

    <span class="hljs-comment">/* Assigning integers */</span>
    mpz_set_str(num_a, <span class="hljs-string">"3479349783486297692763769376273723897236"</span>, <span class="hljs-number">10</span>);
    mpz_set_str(num_b, <span class="hljs-string">"9223372036854775807"</span>, <span class="hljs-number">10</span>);

    <span class="hljs-comment">/* Addition */</span>
    mpz_add(res, num_a, num_b);
    gmp_printf(<span class="hljs-string">"Addition:\n%Zd + %Zd = %Zd\n\n"</span>, num_a, num_b, res);

    <span class="hljs-comment">/* Clearing memory */</span>
    mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);

    <span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>);
}
</code></pre>
<p>You need to link the GMP library when compiling your program. You can only link the dynamic or static library if you have installed GMP on your machine. If you haven’t, go back to the installation section above.</p>
<p>Run the command below to build your program. The <code>-lgmp</code> flag tells gcc to search for the GMP library when linking. GCC will search the list of standard directories to find the library.</p>
<pre><code class="lang-bash">gcc main.c -o main -lgmp
</code></pre>
<p>If it could not find the GMP library on your machine. Try with the build flags below. The <code>-L~/gmp-6.2.1/.libs</code> flag tells gcc to also check the <code>~/gmp-6.2.1/.libs</code> directory if it could not find the library using the standard list. For you, this path is the location you installed GMP.</p>
<pre><code class="lang-bash">gcc main.c -o main -L~/gmp-6.2.1/.libs -lgmp -static
</code></pre>
<p>That covers how you can add large numbers in C and build your program.</p>
<h3 id="heading-subtraction">Subtraction</h3>
<p>You can use the <code>mpz_sub</code> function from the GMP library to subtract large numbers. Ensure you initialize the variables and assign their integers respectively.</p>
<p>This subtracts <code>num_b</code> from <code>num_a</code> and assigns the result to <code>res</code>.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Subtraction */</span>
mpz_sub(res, num_b, num_a);
gmp_printf(<span class="hljs-string">"Substraction:\n%Zd - %Zd = %Zd\n\n"</span>, num_a, num_b, res);
</code></pre>
<p>Your full program might look like this.</p>
<pre><code class="lang-c"><span class="hljs-comment">// main.c</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;gmp.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    <span class="hljs-keyword">mpz_t</span> res, num_a, num_b;

    <span class="hljs-comment">/* Initializing integers */</span>
    mpz_init(res), mpz_init(num_a), mpz_init(num_b);

    <span class="hljs-comment">/* Assigning integers */</span>
    mpz_set_str(num_a, <span class="hljs-string">"3434234245245245252452452452"</span>, <span class="hljs-number">10</span>);
    mpz_set_str(num_b, <span class="hljs-string">"9999943444444434344444444434232323232322"</span>, <span class="hljs-number">10</span>);

    <span class="hljs-comment">/* Subtraction */</span>
    mpz_sub(res, num_a, num_b);
    gmp_printf(<span class="hljs-string">"Substraction:\n%Zd - %Zd = %Zd\n\n"</span>, num_a, num_b, res);

    <span class="hljs-comment">/* Clearing memory */</span>
    mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);

    <span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>);
}
</code></pre>
<h3 id="heading-multiplication">Multiplication</h3>
<p>For multiplying integers, use <code>mpz_mul</code> function from the GMP library.</p>
<p>This multiplies <code>num_a</code> and <code>num_b</code> and assigns results to <code>res</code>.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Multiplication */</span>
mpz_mul(res, num_a, num_b);
gmp_printf(<span class="hljs-string">"Multiplication:\n%Zd x %Zd = %Zd\n\n"</span>, num_a, num_b, res);
</code></pre>
<h3 id="heading-division">Division</h3>
<p>For division, things will look a little different. Instead of using the type <code>mpz_t</code> to declare integers as you have seen before, you will use <code>mpf_t</code> instead to declare floats.</p>
<p>To divide large numbers using GMP you need to declare and initialize floats and not integers.</p>
<pre><code class="lang-c"><span class="hljs-keyword">mpf_t</span> div_res, div_a, div_b;
</code></pre>
<p>Then you initialize the variables using <code>mpf_init</code>.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Initializing floats */</span>
mpf_init(div_res), mpf_init(div_a), mpf_init(div_b);
</code></pre>
<p>Assign values you want to the variables. They can be as large as needed. The last argument to <code>mpf_set_str</code> tells GMP that the string is in a decimal format.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Assign floats */</span>
mpf_set_str(div_a, <span class="hljs-string">"7347973477376467734.34322335550000000000"</span>, <span class="hljs-number">10</span>);
mpf_set_str(div_b, <span class="hljs-string">"489384838948848.4783873847"</span>, <span class="hljs-number">10</span>);
</code></pre>
<p>Divide and print out the results using the functions below. The GMP function <code>mpf_div</code> divides <code>div_a</code> by <code>div_b</code> and assigns the result to <code>div_res</code>. Then prints out the formatted string.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Division */</span>
mpf_div(div_res, div_a, div_b);
gmp_printf(<span class="hljs-string">"Division:\n%Ff / %Ff = %Ff\n\n"</span>, div_a, div_b, div_res);
</code></pre>
<p>Your final code should look like this.</p>
<pre><code class="lang-c"><span class="hljs-comment">// main.c</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;gmp.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
    <span class="hljs-keyword">mpf_t</span> div_res, div_a, div_b;

    <span class="hljs-comment">/* Initializing floats */</span>
    mpf_init(div_res), mpf_init(div_a), mpf_init(div_b);

    <span class="hljs-comment">/* Assign floats */</span>
    mpf_set_str(div_a, <span class="hljs-string">"7347973477376467734.34322335550000000000"</span>, <span class="hljs-number">10</span>);
    mpf_set_str(div_b, <span class="hljs-string">"489384838948848.4783873847"</span>, <span class="hljs-number">10</span>);

    <span class="hljs-comment">/* Division */</span>
    mpf_div(div_res, div_a, div_b);
    gmp_printf(<span class="hljs-string">"Division:\n%Ff / %Ff = %Ff\n\n"</span>, div_a, div_b, div_res);

    <span class="hljs-comment">/* Clearing memory */</span>
    mpf_clear(div_res), mpf_clear(div_a), mpf_clear(div_b);

    <span class="hljs-keyword">return</span> (<span class="hljs-number">0</span>);
}
</code></pre>
<h3 id="heading-square-root">Square root</h3>
<p>Ensure you declare and initialize the float variables. Then calculate the square root of that variable using <code>mpf_sqrt</code> function. This function only accepts two arguments. The variable to square root and the variable to assign the result.</p>
<pre><code class="lang-c"><span class="hljs-comment">/* Squre root */</span>
mpf_sqrt(div_res, div_a);
gmp_printf(<span class="hljs-string">"Square root:\nsqrt(%Ff) = %Ff\n"</span>, div_a, div_res);
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You can perform other arithmetical operations that are not covered in this article using GMP. Check out the resources section below for their documentation to learn more. It covers how you can perform more Arithmetical operations with Logical and Bitwise operations. Also, you can calculate using C int types and rational numbers.</p>
<p>Use the resources provided below to learn more about working with big numbers in C using the GMP library. If you are looking for a challenge try writing a C function to add two large numbers.</p>
<p>Thanks for reading this article. 😊</p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><p>Linking libraries using GCC Compiler - <a target="_blank" href="https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html">https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html</a></p>
</li>
<li><p>Installing GMP from the official website - <a target="_blank" href="https://gmplib.org/#DOWNLOAD">https://gmplib.org/#DOWNLOAD</a></p>
</li>
<li><p>Guide to installing GMP on any machine - <a target="_blank" href="http://rstudio-pubs-static.s3.amazonaws.com/493124_a46782f9253a4b8193595b6b2a037d58.html">http://rstudio-pubs-static.s3.amazonaws.com/493124_a46782f9253a4b8193595b6b2a037d58.html</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Mastering Django CI/CD using GitHub Actions]]></title><description><![CDATA[Testing and delivery is a common repetitive cycle in application development. This cycle consumes more time and resources as we fix or add more features to our application. Automating this repetitive process will reduce the time spent in application ...]]></description><link>https://blog.covenlabs.space/mastering-django-cicd-using-github-actions</link><guid isPermaLink="true">https://blog.covenlabs.space/mastering-django-cicd-using-github-actions</guid><category><![CDATA[github-actions]]></category><category><![CDATA[Django]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Python]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Wed, 05 Jul 2023 11:21:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688533774112/6b3db281-8551-45b4-95dd-6daa705a86dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Testing and delivery is a common repetitive cycle in application development. This cycle consumes more time and resources as we fix or add more features to our application. Automating this repetitive process will reduce the time spent in application development.</p>
<p>Testing and Deployment are part of the cycle discussed earlier. We build, deploy and test our applications a lot. Doing this every time is vulnerable to human error. Automating our tests guarantees that every commit undergoes testing.</p>
<p>This article covers how we can use GitHub Actions to automatically test our Django applications.</p>
<p>Let’s dive in.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow through with this article, we need the following:</p>
<ul>
<li><p>Basic knowledge of Django, Git, and GitHub</p>
</li>
<li><p>A GitHub account</p>
</li>
<li><p>Python3 and Django installed on our operating system</p>
</li>
</ul>
<h2 id="heading-setup-demo-django-application">Setup Demo Django Application</h2>
<p>We need a Django application that has tests to understand how GitHub actions work. We can work with this <a target="_blank" href="https://github.com/devvspaces/simple-django-testcase">demo Django project</a>, which includes tests.</p>
<p>GitHub actions run on GitHub repositories and not on our machines. Only the owner of the repository can manage workflow runs. Later in the article, we will cover what Workflows are.</p>
<p>We need to fork the repository and clone it.</p>
<pre><code class="lang-python">git clone &lt;REPOSITORY_URL&gt;
</code></pre>
<p>We should set up a new virtual environment.</p>
<pre><code class="lang-bash">
<span class="hljs-comment"># linux and mac</span>
<span class="hljs-built_in">cd</span> &lt;PROJECT_DIR&gt;
python3 -m venv venv
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<pre><code class="lang-python">
<span class="hljs-comment"># windows</span>
cd &lt;PROJECT_DIR&gt;
python3 -m venv venv
venv/Scripts/activate  <span class="hljs-comment"># &lt;-- difference</span>
</code></pre>
<p>Now we need to install the project dependencies. Run this command in the project directory. This will install all the dependencies specified in <code>requirements.txt</code> file.</p>
<pre><code class="lang-python">pip install -r requirements.txt
</code></pre>
<p>Now that our application setup is complete. Let’s run our tests will. The tests confirm the reliability of our application.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> project
python manage.py <span class="hljs-built_in">test</span>
</code></pre>
<p>The tests are successful. We can now go ahead and automate this process using GitHub actions.😊</p>
<blockquote>
<p>Automated tests don’t only work when we use Django’s built-in test runners. We can write automation for any kind of test runners we are using. One popular test runner in the Python community is Pytest.</p>
</blockquote>
<h2 id="heading-what-are-github-actions">What are GitHub Actions?</h2>
<p>To get started, we need to define a <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/about-workflows">workflow</a>. A workflow is a configurable automated process that will run one or more jobs. A step is a command or action that performs a basic task. An Action is a collection of steps, which makes an action reusable. A Job is an operation in a workflow that contains steps. Jobs can run in parallel or in sequence.</p>
<p>We define workflows by using a <code>YAML</code> file checked in the repository. A workflow will execute when triggered by an event in the same repository it exists.</p>
<p>GitHub workflows listen to many events, examples are push and pull requests. The events configured into our <code>YAML</code> file triggers our workflow. For example, when we push a new commit to the master branch, this can trigger a testing workflow.</p>
<h2 id="heading-creating-a-testing-workflow">Creating A Testing Workflow</h2>
<p>Let’s create a workflow that executes our Django application tests.</p>
<blockquote>
<p>Workflows are not for testing but for executing jobs which can be anything. An example of this is running tests. Our tests are already defined. We configure workflows to execute them. Other use cases are deployments and closing pull requests.</p>
</blockquote>
<p>Create a new directory called .github/workflows in the root directory. Create a new file called <code>test.yml</code> in the .github/workflows directory. This file will be our workflow <code>YAML</code> configuration.</p>
<pre><code class="lang-yml">
<span class="hljs-comment"># test.yml</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Django</span> <span class="hljs-string">Tests</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">master</span>]
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test-django-app:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">fail-fast:</span> <span class="hljs-literal">false</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">python-version:</span> [<span class="hljs-string">"3.9"</span>]
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">fetch-depth:</span> <span class="hljs-number">0</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Python</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.python-version</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">python-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.python-version</span> <span class="hljs-string">}}</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          python -m pip install --upgrade pip
          if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Django</span> <span class="hljs-string">test</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          cd project
          python manage.py test</span>
</code></pre>
<p>Let’s break down what each syntax means and how this executes the application tests.</p>
<p>We start by defining the workflow name by using the name syntax.</p>
<pre><code class="lang-python">name: Run Django Tests
</code></pre>
<p>The workflow name helps us identify the workflow in our repository’s GitHub Actions tab.</p>
<blockquote>
<p>The GitHub Actions tab helps us to manage workflow runs. See how to manage a workflow run on GitHub.</p>
</blockquote>
<p>Next, we define the event that triggers the workflow.</p>
<pre><code class="lang-python">on:
  push:
    branches: [master]
</code></pre>
<p>By using the on <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on">syntax</a>, every commit we push to the master branch triggers the workflow run. We can specify many events and branches.</p>
<p>Next, we have the <a target="_blank" href="https://docs.github.com/en/actions/using-jobs/using-jobs-in-a-workflow">jobs syntax</a>.</p>
<pre><code class="lang-python">jobs:
  test-django-app:
</code></pre>
<p>A scenario to use this is when we want to deploy a web application after successful tests. We can create two jobs, one for testing and the other for deployment. Then configure the deployment to run after when tests are complete and successful.</p>
<blockquote>
<p>The name of our job is test-django-app, we can name it anything. But make sure it’s descriptive, as it helps us identify the currently running job in the GitHub Actions tab.</p>
</blockquote>
<p>Next, the <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on">runs-on syntax</a> defines what machine will run the job. Here we instructed it to use <code>ubuntu-latest</code> version.</p>
<pre><code class="lang-python">runs-on: ubuntu-latest
</code></pre>
<p>Next, the <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategy">strategy syntax</a> helps us define what Python versions we will use to test. In our workflow, we have defined only one version. The job will use each Python version declared in the list to execute itself in parallel.</p>
<pre><code class="lang-python">strategy:
  fail-fast: false
  matrix:
    python-version: [<span class="hljs-string">"3.9"</span>]
</code></pre>
<p><code>fail-fast</code> applies to the entire matrix. If <code>fail-fast</code> is set to <code>true</code>, GitHub will cancel all in-progress and queued jobs in the matrix if any job in the matrix fails. This property defaults to <code>true</code>.</p>
<p>Assuming that we built a Python package and set many Python versions. We can ensure the package undergoes testing across defined Python versions.</p>
<p>Jobs contain a sequence of tasks called <a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsteps">steps</a>. Steps can run commands, set up docker, or run an action in our repository. These steps run one after the other based on their position in the <code>YAML</code> definition.</p>
<p>The following are the actions taken by each step in our workflow:</p>
<ol>
<li><p>Checkout the repository on the machine defined for the job,</p>
</li>
<li><p>Setup Python using the current version from the strategy,</p>
</li>
<li><p>Install pip and the project dependencies,</p>
</li>
<li><p>Move into the project directory and run the tests.</p>
</li>
</ol>
<p>We need to commit and push a new workflow to trigger our workflow.</p>
<pre><code class="lang-python">git add .
git commit -m <span class="hljs-string">"Added tests automation using Github Actions"</span>
git push
</code></pre>
<p>We should see a new running or completed workflow run on the GitHub actions tab in our forked repository.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/721sg5m1i926rksaw22x.png" alt="GitHub workflow actions running page" /></p>
<p>This workflow would show us each job and the steps executed.</p>
<p>![GitHub workflow job management tab(<a target="_blank" href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tlk6am6n0dhwjn7s2mn.png">https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tlk6am6n0dhwjn7s2mn.png</a>)</p>
<p>Now, any time we push a new commit to the master branch. Our workflow executes our Django application tests.</p>
<p><a target="_blank" href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Understanding GitHub Actions</a> is a complete guide to learning actions, workflows, and jobs. Check it out to master project development automation.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we have covered how GitHub actions execute Django application tests. Continuous Integration and Delivery is an important part of a modern development cycle. Automating development life cycles ensures we build reliable applications when working with collaborators.</p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><p><a target="_blank" href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Understanding GitHub Actions</a> by GitHub</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/training/modules/introduction-to-github-actions/">Introduction to GitHub Actions Training</a> by Microsoft</p>
</li>
<li><p><a target="_blank" href="https://www.learnenough.com/blog/git-actions-tutorial">GitHub Actions Tutorial for Beginners</a> to Automate Your Workflow</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Dynamically Managing Dependencies In Your Python Projects]]></title><description><![CDATA[In today's software development landscape, ensuring successful project deployment can be challenging due to the variety of environments programmers use to build their projects. Each environment presents unique challenges to project deployment from Wi...]]></description><link>https://blog.covenlabs.space/dynamically-managing-dependencies-in-your-python-projects</link><guid isPermaLink="true">https://blog.covenlabs.space/dynamically-managing-dependencies-in-your-python-projects</guid><category><![CDATA[Python]]></category><category><![CDATA[pypi]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Wed, 03 May 2023 09:02:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683103252279/2b3a87cf-4f34-4933-bc55-a269a79771fa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's software development landscape, ensuring successful project deployment can be challenging due to the variety of environments programmers use to build their projects. Each environment presents unique challenges to project deployment from Windows to ArchLinux, Mac to Ubuntu.</p>
<p>One major challenge developers face is conflicting environment dependencies, which can cause project failure when deployed. Although Docker solves this problem, its complex setup requirements make it inaccessible to many developers.</p>
<p>This tutorial offers a solution by demonstrating how to dynamically install Python dependencies based on the environment in which the project will run.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>With only a basic understanding of Python and Git, any developer can follow the methods outlined in this tutorial to improve their project's deployment success. The only requirement to have installed for this tutorial is Python. To install Python, visit their official downloads page.</p>
<h2 id="heading-what-is-the-problem">What is the problem?</h2>
<p>When using Postgres database with Django, psycopg2 database adapter is a required dependency for this to work. But there is a problem, psycopg2 will install successfully on a Windows environment but won't on a Linux environment, you will need to install psycopg2-binary instead.</p>
<p>Well, if your development and deployment environment is similar or you use Docker, you won't have a problem with this situation. The problem occurs when you have differing environments or multiple collaborators working on the project with you. You don't want them editing the requirements.txt file so as not to cause git conflicts.</p>
<h2 id="heading-how-can-this-problem-be-solved">How can this problem be solved?</h2>
<p>Two major methods will be shared today to help you dynamically install Python dependencies based on your environment or Python version.</p>
<h2 id="heading-conditional-pip-requirements-syntax">Conditional pip requirements syntax</h2>
<p>Suppose that the dependencies listed in your requirements.txt file are as follows:</p>
<pre><code class="lang-txt">requests==2.26.0
six==1.16.0
urllib3==1.26.7
psycopg2==2.9.6
</code></pre>
<p>That can be modified to ensure that when you install the requirements on a Linux environment, the required database adapter for Linux will be installed.</p>
<pre><code class="lang-txt">requests==2.26.0
six==1.16.0
urllib3==1.26.7
psycopg2-binary==2.9.3; sys_platform == "linux"
psycopg2==2.9.6; sys_platform == "win32"
</code></pre>
<p>You can also program the dependencies to be installed based on the Python version installed on the environment.</p>
<pre><code class="lang-txt">requests==2.26.0; python_version &gt; '3.0'
requests==2.26.0; python_version == '2.6'
six==1.16.0
urllib3==1.26.7
psycopg2-binary==2.9.3; sys_platform == "linux"
psycopg2==2.9.6; sys_platform == "win32"
</code></pre>
<p>They are defined in PEP 508 and PEP 0345 (Environment Markers), but the syntax appears to follow the draft PEP 0496.</p>
<p>To know all the possible values for <code>sys_platform``,</code> visit this StackOverflow answer.</p>
<p>Now when you run <code>pip install -r requirements.txt</code>, depending on your environment, the appropriate dependency and version will be installed.</p>
<p>This is the easiest and recommended method for dynamically installing dependencies based on the environment or Python version.</p>
<h3 id="heading-python-install-script">Python install script</h3>
<p>You could create an <a target="_blank" href="http://install.py">install.py</a> script to install dependencies based on the environment or Python version.</p>
<ul>
<li><p>Create a file <a target="_blank" href="http://install.py">install.py</a> in your project's root directory</p>
<p>  ```python
  import pip</p>
<p>  <em>all</em> = (
      "requests==2.26.0",
      "six==1.16.0",
      "urllib3==1.26.7",
  )  # All platforms</p>
<p>  windows = ("psycopg2==2.9.6",)  # Windows</p>
<p>  linux = ("psycopg2-binary==2.9.3",)  # Linux</p>
<p>  darwin = []  # MacOS</p>
</li>
</ul>
<p>    def install(packages):
        print("Installing packages: {}".format(packages))
        for package in packages:
            pip.main(['install', package])</p>
<p>    if <strong>name</strong> == '<strong>main</strong>':</p>
<p>        from sys import platform</p>
<p>        print("Platform: {}".format(platform))</p>
<p>        install(<em>all</em>)</p>
<p>        if platform == 'win32':
            install(windows)
        if platform.startswith('linux'):
            install(linux)
        if platform == 'darwin':
            install(darwin)</p>
<p>        print("Completed installation of packages.")</p>
<pre><code>

This script works by checking what platform the program is running on using the Python built-<span class="hljs-keyword">in</span> sys package. So it installs the defined dependencies <span class="hljs-keyword">for</span> that platform by calling <span class="hljs-string">`pip`</span> by script. This method is more complex and time-consuming, but it gives you more control and flexibility on the program control flow.

* Run the program to install the packages

    <span class="hljs-string">``</span><span class="hljs-string">`bash
    python install.py</span>
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, conflicting environment dependencies can be a huge headache for software developers when deploying their projects. Fortunately, several solutions are available, including Docker and the dynamic installation of dependencies based on the environment. In this article, we have provided two different methods for dynamically installing Python dependencies based on the environment, which can help avoid conflicts and ensure the project runs smoothly across different platforms. These methods allow developers to save time, reduce errors, and focus on building great software. I hope that this article has been helpful in providing useful tips and tricks for managing environment dependencies in your Python projects.</p>
<p>Thanks for reading, I'd also love to connect with you at <a target="_blank" href="https://twitter.com/netrobeweb">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/ayomide-ayanwola/">LinkedIn</a> | <a target="_blank" href="http://github.com/devvspaces">GitHub</a> | <a target="_blank" href="https://netrobe.vercel.app/">Portfolio</a>. 🤓</p>
]]></content:encoded></item><item><title><![CDATA[Building a Tech Course Curriculums Platform with MindsDB Models and Django]]></title><description><![CDATA[We often find ourselves overwhelmed by the abundance of free and paid online tech courses and resources. That's why today we will build a platform that curates the best tech course curriculums and organizes them based on skill level, topic, and user ...]]></description><link>https://blog.covenlabs.space/building-a-tech-course-curriculums-platform-with-mindsdb-models-and-django</link><guid isPermaLink="true">https://blog.covenlabs.space/building-a-tech-course-curriculums-platform-with-mindsdb-models-and-django</guid><category><![CDATA[mindsdb]]></category><category><![CDATA[MindsDBHackathon]]></category><category><![CDATA[Python]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sun, 30 Apr 2023 22:59:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682895547311/1f304f75-a620-4b97-a290-62bd23bc1598.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We often find ourselves overwhelmed by the abundance of free and paid online tech courses and resources. That's why today we will build a platform that curates the best tech course curriculums and organizes them based on skill level, topic, and user feedback. To improve the user experience and accelerate app growth, We will integrate MindsDB models for sentiment and text classification into the platform. In this tutorial, We will walk through MindsDB models and Django are used for the backend, and Next.js for the frontend to build this platform.</p>
<h2 id="heading-what-is-mindsdb">What is MindsDB?</h2>
<p>MindsDB is an open-source, automated machine-learning platform that enables developers to build and integrate machine-learning models into their applications quickly and easily. MindsDB provides a simple interface that allows you to train, test, and deploy machine learning models without having to write any code. It also supports a wide range of use cases, such as classification, regression, and time series forecasting.</p>
<h2 id="heading-whats-the-problem">What's the Problem?</h2>
<p>New programmers end up in something called the <a target="_blank" href="https://medium.com/codex/what-is-tutorial-hell-and-how-to-avoid-it-to-improve-as-a-developer-8c5376c97011?source=rss------technology-5#:~:text=Tutorial%20hell%20is%20a%20concept,a%20new%20language%20or%20technology.">Tutorial Hell</a>. Whereby they keep watching and reading various online tutorials from various content creators. Tutorials are good but most don't cover all the aspects a new programmer needs to suceed in a skill.</p>
<h2 id="heading-whats-the-solution">What's the Solution?</h2>
<p>This project is built with the goal of helping new programmers find quality tech curriculums and resources. The platform curates the best resources and organizes them into curriculums based on user feedback. To improve the user experience and accelerate app growth, the platform integrates MindsDB models for sentiment and text classification on user reviews.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682895270482/477b644d-37d2-4d91-846c-ac34d1fc9da5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-why-do-we-need-to-classify-reviews">Why do we need to classify Reviews?</h2>
<p>When users are progressing through a curriculum or have completed it. Their reviews are important so that we can use them to reorganize the curriculums based on user needs and their learning experience.</p>
<p>Using AI to classify user reviews sentimental can help us categorize or filter reviews by priority and what we need to work on ASAP. Doing this manually would be time-consuming and slow down problem analysis and updates.</p>
<h2 id="heading-why-mindsdb-models">Why MindsDB Models?</h2>
<p>In this project, we used MindsDB models for sentiment and text classification to classify user curriculum reviews. The user reviews are classified by labels and sentiment. MindsDB models are used because it's easier to integrate than to install Pytorch and LLM (Large Language models).</p>
<p>We can train our models right in the MindsDB SQL editor. Yes, we will use SQL queries to train our AI models. <a target="_blank" href="https://docs.mindsdb.com/nlp/nlp-mindsdb-hf">MindsDB NLP engine</a> is currently powered by Hugging Face and Open AI. It supports NLP tasks like Text Classification and Zero-Shot Classification.</p>
<p>By using MindsDB Python SDK, we can easily connect to our MindsDB Cloud Server and execute AI queries on our pre-trained models with just a few lines of Python code. MindsDB's large community and learning resources can help us to find solutions on how to use them to solve any problems we might encounter.</p>
<h2 id="heading-building-the-project">Building The Project</h2>
<p>We will cover the project build-up from the DB design to the product mvp. The repository for the completed project <a target="_blank" href="https://github.com/devvspaces/roadflow-api">Backend API</a> and <a target="_blank" href="https://github.com/devvspaces/roadflow-web">Frontend Web</a> contain installation guides to set up the project and start using it.</p>
<h2 id="heading-project-prerequisites">Project Prerequisites</h2>
<p>To follow through with this article, we need:</p>
<ul>
<li><p>A <a target="_blank" href="https://mindsdb.com/">MindsDB</a> cloud account. Create a free cloud account at <a target="_blank" href="http://cloud.mindsdb.com"><strong>cloud.mindsdb.com</strong></a><strong>.</strong></p>
</li>
<li><p><a target="_blank" href="https://python.org/">Python</a> and <a target="_blank" href="https://nodejs.org/en">NodeJs</a> installed.</p>
</li>
<li><p><a target="_blank" href="https://redis.io/">Redis</a> for caching</p>
</li>
<li><p>Basic knowledge of <a target="_blank" href="https://www.djangoproject.com/">Django</a>, <a target="_blank" href="https://www.django-rest-framework.org/">Django Rest Framework</a>, <a target="_blank" href="https://react.dev/">React</a>, and <a target="_blank" href="https://nextjs.org/">NextJs</a> frameworks</p>
</li>
</ul>
<blockquote>
<p>Django Memcache can be configured instead of redis if problem occurs when installing redis.</p>
</blockquote>
<p>Let's start building 🤓💻</p>
<h2 id="heading-productivity-foundations">Productivity Foundations</h2>
<h3 id="heading-database-design">Database Design</h3>
<p>First of we need to have an understanding of how the Database will be structured. By using <a target="_blank" href="https://dbdiagram.io/">dbdiagram.io</a>, we can design relation database structures. Here is a <a target="_blank" href="https://dbdiagram.io/d/6437cb1c8615191cfa8d9bc1">database diagram</a> that we can use.</p>
<p><img src="https://github.com/devvspaces/roadflow-api/raw/dev/Roadflow%20DB.png" alt /></p>
<p>This can help us get clarity on how the project will be structured. That's like 50% of the problem-solving done here. We would find out tables related to each other and how to categorize the apps in Django. This saved will save a lot of time instead of jumping on the project without direction.</p>
<p>Need the DB Schema used to generate the DB diagram - visit <a target="_blank" href="https://dbdiagram.io/d/6437cb1c8615191cfa8d9bc1">here</a>.</p>
<h3 id="heading-flow-design">Flow Design</h3>
<p>Here is the link to the <a target="_blank" href="https://www.figma.com/file/4sWAOaXGdd16N5AlyFVSBl/RoadTrack-Project?type=whiteboard&amp;node-id=0%3A1&amp;t=83f2QIdz8PNYJJ4D-1">Figma jam</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682941158904/093c3c1d-5005-4a5f-b812-a4e971ce5c05.png" alt class="image--center mx-auto" /></p>
<p>Having a simple design for the application flow will go a long way to help us have a working application in our minds. Also finding solutions to other basic problems like the best authentication method to use, how to organize the API, and how the user will use the application.</p>
<h2 id="heading-rest-api-development">Rest API Development</h2>
<p>Django and Django Rest Framework are used for API development and documentation. Swagger allows us to test the API endpoints from the documentation itself. The <a target="_blank" href="https://github.com/devvspaces/roadflow-api">backend repository</a> has an installation and usage guide in README.md for setting up the project and testing it with ease.</p>
<p>The API is classified into three major sections:</p>
<ul>
<li><p><strong>Account</strong> - Authentication and Authorization</p>
</li>
<li><p><strong>Curriculum</strong> - Organizing curriculums, enrollments, quizzes, and reviews.</p>
</li>
<li><p><strong>MindsDB Classify</strong> - Classifying texts by sentiments and labels.</p>
</li>
</ul>
<h3 id="heading-account">Account</h3>
<p>When a user registers, they will get an OTP in their email to verify their email. The user's OTP is cached for future validations. After validation, the OTP is deleted from the cache. This Django app has the following features:</p>
<ol>
<li><p>Register</p>
</li>
<li><p>Login</p>
</li>
<li><p>Forget password</p>
</li>
<li><p>Change password</p>
</li>
<li><p>Updating user profile</p>
</li>
</ol>
<p>We used <a target="_blank" href="https://jwt.io/">JWT</a> (JSON Web Tokens) for user authentication. This allows us to have a stateless authentication that the frontend can easily manage. <a target="_blank" href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/">Simple JWT</a> allows us to use JWT in Django Rest Framework.</p>
<h3 id="heading-curriculums">Curriculums</h3>
<p>This is the main application in the Django project. This application supports the following features:</p>
<ul>
<li><p>user enrollments, progress tracking,</p>
</li>
<li><p>quiz creation, quiz submission,</p>
</li>
<li><p>curriculum, syllabus, resources creation,</p>
</li>
<li><p>reviews submission and classification.</p>
</li>
</ul>
<p>The backend repository contains comments that explain how the Models, Views, and Serializers work.</p>
<p>Basically, the user can search for curriculums and enroll in them. An enrolled user can progress through the curriculum syllabus by completing quizzes for each lesson. At the end or anytime while taking the curriculum they can submit reviews any kind of reviews. When a new review is submitted it is classified and updated in the database.</p>
<h2 id="heading-nlp-classification-using-mindsdb">NLP Classification using MindsDB</h2>
<p>Our reviews are classified and stored in the <code>CurriculumReview</code> table.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CurriculumReview</span>(<span class="hljs-params">models.Model</span>):</span>
    <span class="hljs-string">"""Curriculum Review Model"""</span>

    SENTIMENT = (
        (<span class="hljs-string">'POS'</span>, <span class="hljs-string">'Positive'</span>),
        (<span class="hljs-string">'NEG'</span>, <span class="hljs-string">'Negative'</span>),
        (<span class="hljs-string">'NEU'</span>, <span class="hljs-string">'Neutral'</span>),
    )

    LABEL = (
        (<span class="hljs-string">'A'</span>, <span class="hljs-string">'Course Content'</span>),
        (<span class="hljs-string">'B'</span>, <span class="hljs-string">'Exercises'</span>),
        (<span class="hljs-string">'C'</span>, <span class="hljs-string">'Course Structure'</span>),
        (<span class="hljs-string">'D'</span>, <span class="hljs-string">'Learning Experience'</span>),
        (<span class="hljs-string">'E'</span>, <span class="hljs-string">'Support'</span>),
    )

    enrollment = models.ForeignKey(
        CurriculumEnrollment, on_delete=models.CASCADE)
    rating = models.PositiveSmallIntegerField(
        default=<span class="hljs-number">0</span>,
        validators=[MinValueValidator(<span class="hljs-number">1</span>), MaxValueValidator(<span class="hljs-number">5</span>)]
    )
    review = models.TextField(null=<span class="hljs-literal">False</span>, blank=<span class="hljs-literal">False</span>)
    created_at = models.DateTimeField(auto_now_add=<span class="hljs-literal">True</span>)
    updated_at = models.DateTimeField(auto_now=<span class="hljs-literal">True</span>)
    sentiment = models.CharField(
        max_length=<span class="hljs-number">3</span>, null=<span class="hljs-literal">True</span>, blank=<span class="hljs-literal">True</span>,
        choices=SENTIMENT
    )
    label = models.CharField(
        max_length=<span class="hljs-number">1</span>, choices=LABEL, null=<span class="hljs-literal">True</span>, blank=<span class="hljs-literal">True</span>)
</code></pre>
<p>For the sentiment labels, we have:</p>
<pre><code class="lang-python">SENTIMENT = (
    (<span class="hljs-string">'POS'</span>, <span class="hljs-string">'Positive'</span>),
    (<span class="hljs-string">'NEG'</span>, <span class="hljs-string">'Negative'</span>),
    (<span class="hljs-string">'NEU'</span>, <span class="hljs-string">'Neutral'</span>),
)
</code></pre>
<p>For the Zero-Shot classification labels, we have:</p>
<pre><code class="lang-python">LABEL = (
    (<span class="hljs-string">'A'</span>, <span class="hljs-string">'Course Content'</span>),
    (<span class="hljs-string">'B'</span>, <span class="hljs-string">'Exercises'</span>),
    (<span class="hljs-string">'C'</span>, <span class="hljs-string">'Course Structure'</span>),
    (<span class="hljs-string">'D'</span>, <span class="hljs-string">'Learning Experience'</span>),
    (<span class="hljs-string">'E'</span>, <span class="hljs-string">'Support'</span>),
)
</code></pre>
<p>These can then be used as Django Charfield choices, which we can configure in the Django admin for filtering. Allowing us to filter reviews by their labels.</p>
<p>Also, we will see how can reuse this when querying our MindsDB server.</p>
<h3 id="heading-creating-and-training-the-mindsdb-ai-models">Creating and Training the MindsDB AI Models</h3>
<p>First of all, the MindsDB documentation is packed with resources to understand how we can use it.</p>
<p>Today we will be using the following NLP models from <a target="_blank" href="https://huggingface.co/">Hugging Face</a>:</p>
<ul>
<li><p><strong>Sentiment Classification</strong> - <code>cardiffnlp/twitter-roberta-base-sentiment</code></p>
</li>
<li><p><strong>Zero-Shot Classification</strong> - <code>facebook/bart-large-mnli</code></p>
</li>
</ul>
<p>As we have read earlier, MindsDB works seamlessly with Hugging Face NLP models. By running SQL queries in our MindsDB Cloud SQL editor we can easily create and train these models to be used in our project.</p>
<ol>
<li><p>To access our Cloud editor we need to sign in - <a target="_blank" href="https://cloud.mindsdb.com/login">https://cloud.mindsdb.com/login</a>. Don't have an account yet? Create one here <a target="_blank" href="https://cloud.mindsdb.com/login">https://cloud.mindsdb.com</a>.</p>
</li>
<li><p>After signing in, we can see our free demo instance is already set up and running. Click it to access the SQL Editor.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682943961569/c0b23f58-d68b-4cd5-8cb5-04ecad3c4e20.png" alt class="image--center mx-auto" /></p>
<p> On the right panel in the SQL Editor, we can find the Learning Hub with tutorials and resources for using MindsDB SQL Editor.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682944122956/8b1c0613-42b0-4a25-8ed0-3e6a32e1cbaa.png" alt class="image--center mx-auto" /></p>
<p> We can create files, databases, and projects in the SQL Editor. By default, we have a project, mindsdb, already created for us. A project is a collection of data that includes all the necessary information for building, training, and testing a machine-learning model.</p>
</li>
</ol>
<p><strong>A. Training the Sentiment model</strong></p>
<p>Copy and paste the SQL statement below into the editor.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">MODEL</span> mindsdb.hf_sentiment
PREDICT PRED
<span class="hljs-keyword">USING</span>
<span class="hljs-keyword">engine</span> = <span class="hljs-string">'huggingface'</span>,
task = <span class="hljs-string">'text-classification'</span>,
model_name = <span class="hljs-string">'cardiffnlp/twitter-roberta-base-sentiment'</span>,
input_column = <span class="hljs-string">'text'</span>,
labels = [<span class="hljs-string">'Negative'</span>, <span class="hljs-string">'Neutral'</span>, <span class="hljs-string">'Positive'</span>];
</code></pre>
<blockquote>
<p>The labels are from the labels we want to use for sentiment in our Django project.</p>
</blockquote>
<p>In <code>mindsdb.hf_sentiment</code> - <code>mindsdb</code> is the project name while <code>hf_sentiment</code> is the model name. We can use any name for the model name, but we need to take note of it because it will be required in the Django project to access the model.</p>
<p>To run the SQL statement, we need to highlight it in the SQL editor and click on <code>Run</code> towards the top of the screen or <code>Shift + Enter</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682944858571/a89f81d6-bee5-480a-bbb0-5e8a3a7cced2.png" alt class="image--center mx-auto" /></p>
<p>Running the statement creates a new model. To check the status of the hf_sentiment model, run the following statement.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> mindsdb.models 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'hf_sentiment'</span>;
</code></pre>
<p>Status = <code>complete</code> tells us that the model training is complete.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682945159793/d78c05be-2640-4614-a803-4c274e7dffe7.png" alt class="image--center mx-auto" /></p>
<p>To test the model, we run the statement below</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> mindsdb.hf_sentiment
<span class="hljs-keyword">WHERE</span> <span class="hljs-built_in">text</span> = <span class="hljs-string">'I like you. I love you.'</span>;
</code></pre>
<p>This results in a response that contains the prediction <code>PRED_explain</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682945282331/fe676180-a008-41fc-a9c5-d9a2922bb6d5.png" alt class="image--center mx-auto" /></p>
<p>The prediction tells us that the text sounds more Positive than Neutral or Negative. In our Django project, we will need to write a program that retrieves the label with the maximum result.</p>
<p><strong>B. Training the Zero-Shot classification model</strong></p>
<p>Using what we have learned when creating the sentiment model. Let's create one for Zero-Shot too using a similar process.</p>
<p><strong>Create</strong> -&gt; <strong>Check Status</strong> -&gt; <strong>Test</strong></p>
<p>To create the model, run the following statement.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">MODEL</span> mindsdb.hf_classify
PREDICT PRED
<span class="hljs-keyword">USING</span>
<span class="hljs-keyword">engine</span> = <span class="hljs-string">'huggingface'</span>,
task = <span class="hljs-string">'zero-shot-classification'</span>,
model_name = <span class="hljs-string">'facebook/bart-large-mnli'</span>,
input_column = <span class="hljs-string">'text'</span>,
candidate_labels = [<span class="hljs-string">'Course Content'</span>, <span class="hljs-string">'Exercises'</span>, <span class="hljs-string">'Course Structure'</span>, <span class="hljs-string">'Learning Experience'</span>, <span class="hljs-string">'Support'</span>];
</code></pre>
<blockquote>
<p>We also used our Django project labels as the <code>hf_classify</code> labels here too. Also don't forget to note the model name <code>hf_classify</code>.</p>
</blockquote>
<p>To check for the status of the newly created model, run the following statement.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> mindsdb.models 
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'hf_classify'</span>;
</code></pre>
<p>Wait until it's completed training.</p>
<p>To test the model, run the following statement.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> *
<span class="hljs-keyword">FROM</span> mindsdb.hf_classify
<span class="hljs-keyword">WHERE</span> <span class="hljs-built_in">text</span> = <span class="hljs-string">'This is a nice curriculum. Explains a lot about HTML tags and css design. But needs more video contents. Thanks.'</span>;
</code></pre>
<p>We should get the following response.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682946263170/071bb18e-784b-4b71-8152-60fb5641d2e9.png" alt class="image--center mx-auto" /></p>
<p>Telling us that this is a review that tells us how the user feels about the Course Content.</p>
<h3 id="heading-integrating-mindsdb-with-python">Integrating MindsDB with Python</h3>
<p>After following the installation guide in the <a target="_blank" href="https://github.com/devvspaces/roadflow-api/blob/dev/README.md">backend repository README.md</a>, we should have installed the required dependency for integrating MindsDB because it's included in the requirements.txt file in the repository.</p>
<p>This is the MindsDB Python SDK. To install it explicitly using <a target="_blank" href="https://pypi.org/project/pip/">pip</a>, run the following command in the terminal.</p>
<pre><code class="lang-bash">pip install mindsdb-sdk
</code></pre>
<p>This is the program from the <code>src/utils/base/mindsdb.py</code> file in the repository.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> mindsdb_sdk
<span class="hljs-keyword">from</span> django.conf <span class="hljs-keyword">import</span> settings
<span class="hljs-keyword">from</span> Curriculum.models <span class="hljs-keyword">import</span> CurriculumReview

username = settings.MINDSDB_SERVER_USERNAME
password = settings.MINDSDB_SERVER_PASSWORD

server = <span class="hljs-literal">None</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect_server</span>():</span>
    <span class="hljs-keyword">global</span> server
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> server:
        server = mindsdb_sdk.connect(
            <span class="hljs-string">'https://cloud.mindsdb.com'</span>,
            login=username,
            password=password
        )
    <span class="hljs-keyword">return</span> server


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">make_query</span>(<span class="hljs-params">text: str, model: str</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"""
    SELECT *
    FROM mindsdb.<span class="hljs-subst">{model}</span>
    WHERE text = '<span class="hljs-subst">{text}</span>'
    """</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">classify_text</span>(<span class="hljs-params">text: str</span>):</span>
    server = connect_server()
    project = server.get_project(<span class="hljs-string">'mindsdb'</span>)
    max_label = <span class="hljs-string">""</span>
    max_score = <span class="hljs-number">0</span>

    df = project.query(make_query(text, <span class="hljs-string">"hf_classify"</span>)).fetch()
    data = df[<span class="hljs-string">'PRED_explain'</span>][<span class="hljs-number">0</span>]
    <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> CurriculumReview.LABEL:
        current = data.get(v)
        <span class="hljs-keyword">if</span> current &gt; max_score:
            max_score = current
            max_label = k

    <span class="hljs-keyword">return</span> max_label


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sentiment_text</span>(<span class="hljs-params">text: str</span>):</span>
    server = connect_server()
    project = server.get_project(<span class="hljs-string">'mindsdb'</span>)
    max_label = <span class="hljs-string">""</span>
    max_score = <span class="hljs-number">0</span>

    df = project.query(make_query(text, <span class="hljs-string">"hf_sentiment"</span>)).fetch()
    data = df[<span class="hljs-string">'PRED_explain'</span>][<span class="hljs-number">0</span>]
    <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> CurriculumReview.SENTIMENT:
        current = data.get(v)
        <span class="hljs-keyword">if</span> current &gt; max_score:
            max_score = current
            max_label = k
    <span class="hljs-keyword">return</span> max_label
</code></pre>
<p>Let's go through this program 🤓</p>
<ol>
<li><p><strong>Importing the required modules</strong></p>
<pre><code class="lang-python"> <span class="hljs-keyword">import</span> mindsdb_sdk
 <span class="hljs-keyword">from</span> django.conf <span class="hljs-keyword">import</span> settings
 <span class="hljs-keyword">from</span> Curriculum.models <span class="hljs-keyword">import</span> CurriculumReview
</code></pre>
<p> We imported the <code>CurriculumReview</code> model so we can have access the labels defined in it.</p>
<p> The Django setting is imported so we can have access to the <code>MINDSDB_SERVER_USERNAME</code> and <code>MINDSDB_SERVER_PASSWORD</code> defined when we set up the backend project.</p>
</li>
<li><p><strong>Creating a connection to our MindsDB cloud server.</strong></p>
<pre><code class="lang-python"> server = <span class="hljs-literal">None</span>

 <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect_server</span>():</span>
     <span class="hljs-keyword">global</span> server
     <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> server:
         server = mindsdb_sdk.connect(
             <span class="hljs-string">'https://cloud.mindsdb.com'</span>,
             login=username,
             password=password
         )
     <span class="hljs-keyword">return</span> server
</code></pre>
<p> We did it this way so that if the same Django process already has a connection created for the mindsdb_sdk server, we will use it instead of creating it again.</p>
</li>
<li><p><strong>Creating SQL model queries to our</strong> <code>mindsdb</code> <strong>project in the cloud</strong></p>
<pre><code class="lang-python"> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">make_query</span>(<span class="hljs-params">text: str, model: str</span>):</span>
     <span class="hljs-keyword">return</span> <span class="hljs-string">f"""
     SELECT *
     FROM mindsdb.<span class="hljs-subst">{model}</span>
     WHERE text = '<span class="hljs-subst">{text}</span>'
     """</span>
</code></pre>
<p> This function takes the text to classify and the model name, <code>hf_classify</code> or <code>hf_sentiment</code>, and returns a query that we can execute.</p>
</li>
<li><p><strong>Classifying text to label</strong></p>
<pre><code class="lang-python"> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">classify_text</span>(<span class="hljs-params">text: str</span>):</span>
     server = connect_server()
     project = server.get_project(<span class="hljs-string">'mindsdb'</span>)
     max_label = <span class="hljs-string">""</span>
     max_score = <span class="hljs-number">0</span>

     df = project.query(make_query(text, <span class="hljs-string">"hf_classify"</span>)).fetch()
     data = df[<span class="hljs-string">'PRED_explain'</span>][<span class="hljs-number">0</span>]
     <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> CurriculumReview.LABEL:
         current = data.get(v)
         <span class="hljs-keyword">if</span> current &gt; max_score:
             max_score = current
             max_label = k

     <span class="hljs-keyword">return</span> max_label
</code></pre>
<p> We first</p>
<ul>
<li><p>get the connection to our MindsDB cloud</p>
</li>
<li><p>then get the project, <code>mindsdb</code>,</p>
</li>
<li><p>then use the project to make a query to the <code>hf_classify</code> model,</p>
</li>
<li><p>parse the response and get the label with the maximum result.</p>
</li>
</ul>
</li>
<li><p><strong>Classifying text to sentiment</strong></p>
<p> Works exactly like <code>classify_text</code>, we just used <code>CurriculumReview.SENTIMENT</code> when getting the label with the maximum result.</p>
</li>
</ol>
<p>This is a program from <code>/src/Curriculum/api/base/views.py</code> for <code>RateCurriculum</code> view.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">perform_create</span>(<span class="hljs-params">self, serializer</span>):</span>
    cur = self.get_object()
    enrollment = self.request.user\
        .get_curriculum_enrollment(cur)
    review = serializer.save(enrollment=enrollment)

    <span class="hljs-comment"># Classify review here, in live app use cron job</span>
    review.sentiment = sentiment_text(review.review)
    review.label = classify_text(review.review)
    review.save()
</code></pre>
<p>Ensuring the review label is updated when a user submits a new review, we classify it and update the database.</p>
<p>A performance problem here is that the user has to wait for our classification algorithm to work before it returns a response. In a production environment, it will be better to do the labeling later by using a <a target="_blank" href="https://aws.amazon.com/message-queue/#:~:text=A%20message%20queue%20is%20a,once%2C%20by%20a%20single%20consumer.">Queue</a> or <a target="_blank" href="https://gutsytechster.wordpress.com/2019/06/24/how-to-setup-a-cron-job-in-django/">Cron job</a> that classifies reviews in the background.</p>
<h2 id="heading-impact">Impact</h2>
<p>By using MindsDB models, we are able to quickly and accurately classify user curriculum reviews, allowing us to identify and address areas for improvement. Using the MindsDb cloud made it easier to integrate AI into the application. Doing this the manual way will be hard and time-consuming.</p>
<p>This helps us to continually improve the platform and curate the best possible curriculums for users. Additionally, by using Django and Next.js, we are able to build a scalable and secure platform that can handle a large number of users and provide a seamless user experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we showed how to use MindsDB models and Django for the backend to build a tech course curriculums platform. By implementing MindsDB models for sentiment and text classification, we can quickly and accurately classify user curriculum reviews and improve the user experience of your platform. With the power of <a target="_blank" href="https://docs.mindsdb.com/what-is-mindsdb">MindsDB</a>, we can build a scalable and secure platform that provides a seamless user experience.</p>
<p>Explore the features of MindsDB by checking out their <a target="_blank" href="https://docs.mindsdb.com/what-is-mindsdb"><strong>official documentation</strong></a> and joining the <a target="_blank" href="https://mindsdbcommunity.slack.com/join/shared_invite/zt-1syebtjn9-MLT4dYX2U7NVdorPPDnlRg"><strong>Slack community</strong></a>.</p>
<p>Start building today by <a target="_blank" href="https://cloud.mindsdb.com/?_gl=1*1h5q3wc*_ga*MTUxNDYyNjM3NC4xNjgwNjAyMTQ2*_ga_7LGFPGV6XV*MTY4MjMyNDY0OC4yMi4xLjE2ODIzMjQ5OTcuMzkuMC4w"><strong>creating a free MindsDB Cloud account</strong></a>!</p>
<h2 id="heading-want-to-contribute">Want to Contribute?</h2>
<p>This project is <a target="_blank" href="https://opensource.com/resources/what-open-source">Open Source</a> and can help a lot of new developers organize online free content into structured curriculums saving them from the <a target="_blank" href="https://medium.com/codex/what-is-tutorial-hell-and-how-to-avoid-it-to-improve-as-a-developer-8c5376c97011?source=rss------technology-5#:~:text=Tutorial%20hell%20is%20a%20concept,a%20new%20language%20or%20technology.">Tutorial Hell</a>.</p>
<p>Connect with me on <a target="_blank" href="https://twitter.com/netrobeweb"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/ayomide-ayanwola/"><strong>LinkedIn</strong></a> | <a target="_blank" href="http://github.com/devvspaces"><strong>GitHub</strong></a>, and let's work together, Thanks. 🤓💻</p>
]]></content:encoded></item><item><title><![CDATA[Create and Manage Cryptographically Strong Tokens with Python for Better Web Application Security]]></title><description><![CDATA[Secret key management is a crucial aspect of a software engineer's daily routine. In this article, you will explore how to create and manage cryptographically secure keys in Python using the popular Pypi cryptography module. You will also learn the i...]]></description><link>https://blog.covenlabs.space/create-and-manage-cryptographically-strong-tokens-with-python-for-better-web-application-security</link><guid isPermaLink="true">https://blog.covenlabs.space/create-and-manage-cryptographically-strong-tokens-with-python-for-better-web-application-security</guid><category><![CDATA[Python]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[Security]]></category><category><![CDATA[Environment variables]]></category><category><![CDATA[KeyManagement]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Fri, 14 Apr 2023 20:48:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1678794815797/ef7a2907-66e4-498a-815a-a6abd59d5cb3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Secret key management is a crucial aspect of a software engineer's daily routine. In this article, you will explore how to create and manage cryptographically secure keys in Python using the popular Pypi cryptography module. You will also learn the importance of securely storing these keys to ensure maximum protection of sensitive data in your web applications and software.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You must install Python on your machine if you don't have it installed. It’s the only needed external requirement. You can install Python from their official <a target="_blank" href="https://www.python.org/downloads/">downloads</a> page. It’s recommended to install the latest version of Python for this tutorial.</p>
<p>To follow up with this tutorial, you are required to have some knowledge about writing simple Python programs. All the packages that will be discussed are from the Python standard library or Pypi package manager.</p>
<h2 id="heading-secured-symmetrical-encryption-keys">Secured Symmetrical Encryption Keys</h2>
<p>When it comes to encryption and decryption in Python, the Pypi cryptography module is a popular choice. One of the easiest and most secure ways to implement symmetric cryptography using this module is through Fernet symmetrical encryption. However, to use Fernet keys for symmetric encryption, they must be generated and stored securely.</p>
<p><strong>Let's dive in.</strong></p>
<p>Start by creating a new Python project and set up your virtual environment to separate your project dependencies from your global dependencies.</p>
<pre><code class="lang-bash">python -m venv venv
<span class="hljs-comment"># or</span>
python3 -m venv venv
</code></pre>
<p>The Python command above is possible with Python3. If you have any errors setting this up, check out Python's official <a target="_blank" href="https://docs.python.org/3/library/venv.html#creating-virtual-environments">venv documentation</a> to learn about creating a virtual environment.</p>
<ul>
<li>Activate the created environment</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-comment"># Windows: cmd.exe</span>
venv\Script\activate

<span class="hljs-comment"># Linux: bash or Mac: zsh</span>
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<blockquote>
<p><em>Depending on your shell, the command for activating your virtual environment will be different. Check this</em> <a target="_blank" href="https://docs.python.org/3/library/venv.html#how-venvs-work"><em>reference</em></a> <em>for the command that will work for your shell.</em> </p>
</blockquote>
<ul>
<li>Now you need to install <code>cryptography</code></li>
</ul>
<pre><code class="lang-bash">pip install cryptography
</code></pre>
<p>If you encounter any installation issues, you can check out its <a target="_blank" href="https://cryptography.io/en/latest/installation/">installation guide</a>.</p>
<p>Enter the Python shell and run the following commands to generate the key.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> cryptography.fernet <span class="hljs-keyword">import</span> Fernet
<span class="hljs-meta">&gt;&gt;&gt; </span>key = Fernet.generate_key()
<span class="hljs-string">b'RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY='</span>
</code></pre>
<p>The value <code>RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY=</code> in the byte string is the important key. It's stored like that because that's what the cryptography library likes to work with. So, if you generate a new key in the future, you need to convert it to bytes before passing it to any hash function.</p>
<h3 id="heading-is-fernetgeneratekey-cryptographically-secure">Is Fernet.generate_key() cryptographically secure?</h3>
<p>The answer is a resounding <strong>YES!</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678703995808/4320fe8e-3dba-4eeb-a30f-2899445182d2.png" alt class="image--center mx-auto" /></p>
<p>The implementation of Fernet.generate_key method uses the function os.urandom, which has more sufficient randomness than the random function from the built-in random module.</p>
<p>Why? It's because os.urandom cannot be seeded like random and draws its source of entropy from many unpredictable sources, making it more random. For more understanding, you can check this StackOverflow <a target="_blank" href="https://stackoverflow.com/a/47515179">answer</a>.</p>
<p>Now you can use your securely generated key to encrypt and decrypt data.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Initialize a Fernet object</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>f = Fernet(key)

<span class="hljs-comment"># Generate a cryptographically secure and url-safe fernet token</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>token = f.encrypt(<span class="hljs-string">b"Hashnode Neptune is the best"</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>print(token)
<span class="hljs-string">b'gAAAAABkDv-R51WpztocZoMMat3UyKg8jz6KgCQgCq4g9SU36OF7kiPhqQwjLXPT-39lbb5cL-MlUWSmoDLKXlkOZo2Od_Icp_6jPFLDgF32f2r9agrRr50='</span>
</code></pre>
<p>There you have it. You have generated a secure token that you can use to ensure your data security in your projects.</p>
<blockquote>
<p><em>If you don't want to use the generate_key function to create your Fernet tokens. You can use this</em> <a target="_blank" href="https://stackoverflow.com/a/72765116"><em>resource</em></a> <em>to generate a more secure and strong token using the PBKDF2HMAC algorithm.</em></p>
</blockquote>
<h2 id="heading-securely-managing-your-secret-keys">Securely Managing Your Secret Keys</h2>
<p>To ensure complete security, you must store your keys safely. Never share with anyone.</p>
<p>One easy way to do this is to use Pypi <a target="_blank" href="https://pypi.org/project/python-decouple/">decouple</a>.</p>
<ul>
<li>Let's start by installing it in our environment.</li>
</ul>
<pre><code class="lang-python">pip install python-decouple
</code></pre>
<ul>
<li>Create a file <code>.env</code> in your project directory. Add the key generated earlier to the file.</li>
</ul>
<pre><code class="lang-plaintext">SECRET_KEY="RAuFlYBGswBmBOccV13UNYXxJTi19LCGhUOLZOi6oFY="
</code></pre>
<p><strong>Save the file.</strong></p>
<ul>
<li>Create a new Python program, <code>main.py</code>, in your project directory. Then paste the code added below into the file.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

SECRET_KEY = config(<span class="hljs-string">'SECRET_KEY'</span>)

print(SECRET_KEY)
</code></pre>
<p>Run the <code>main.py</code> python program.</p>
<pre><code class="lang-bash">python main.py
</code></pre>
<p>The secret key stored in the environment file would be displayed. Decouple is a project used to store the environment and secret keys. You can read more at <a target="_blank" href="https://pypi.org/project/python-decouple/">Pypi Decouple</a>.</p>
<p>What makes this approach better than using an operating system environment? Because it makes it easier to share secrets when collaborating with others. They only need to clone the project and copy the <code>.env</code> file.</p>
<p>Also, it eliminates the collision of similar keys on multiple projects on the same machine. As a bonus, you can create a file <code>env.example</code>, this file will contain the keys from the actual .env file but with fake values.</p>
<p>Your collaborator can then;</p>
<ol>
<li><p>Create their <code>.env</code> file,</p>
</li>
<li><p>Copy the contents of the <code>env.example</code> file into their <code>.env</code> file,</p>
</li>
<li><p>Generate a secret key,</p>
</li>
<li><p>Replace the sample (fake) key in the <code>.env</code> file with the newly generated key.</p>
</li>
</ol>
<blockquote>
<p><em>Ensure you don't forget to add</em> <code>.env</code> <em>file to</em> <code>.gitignore</code> <em>so it doesn't get pushed to your GitHub repository, thereby exposing your keys. It's better to have a sample file like</em> <code>env.example</code> <em>which can be pushed to keep track of what keys a collaborator needs to create when running the project on their machine.</em></p>
</blockquote>
<h2 id="heading-using-python-built-in-secrets-library">Using Python Built-in Secrets Library</h2>
<blockquote>
<p><a target="_blank" href="https://docs.python.org/3/library/secrets.html#:~:text=The%20secrets%20module%20is%20used%20for%20generating%20cryptographically%20strong%20random%20numbers%20suitable%20for%20managing%20data%20such%20as%20passwords%2C%20account%20authentication%2C%20security%20tokens%2C%20and%20related%20secrets.">From Python Documentation</a>: The <code>secrets</code> module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.</p>
</blockquote>
<p>Use the Secrets library for security purposes to generate something random, like random tokens, digits, or strings. Its randomness is cryptographically secure.</p>
<p><strong>Creating a secure hex token</strong></p>
<ul>
<li>Run your Python shell.</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">import</span> secrets
<span class="hljs-meta">&gt;&gt;&gt; </span>secrets.token_hex()
<span class="hljs-string">'20a3f7333abd0668e474d393870a0b47463a6935e2eb730343820767eaf77226'</span>
</code></pre>
<p>That's a simple way to create a very secure token. The longer the token the more sufficient the randomness.</p>
<p>The function <code>token_hex</code> accepts a parameter, <code>n_bytes</code>, for how long you want the token.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">import</span> secrets
<span class="hljs-meta">&gt;&gt;&gt; </span>secrets.token_hex(<span class="hljs-number">64</span>
<span class="hljs-string">'5222cffc8c2881afcbf219c90c6e2f3a8b168c7547f790c2e852a047e9f4c8094577d8198a1d802ee053d13987e9111b317a7771c9ce87597a67203311afc69f'</span>)
</code></pre>
<p><a target="_blank" href="https://docs.python.org/3/library/secrets.html">Read more in the Python Documentation</a></p>
<p>Now you can use generate highly secure tokens for your projects. These tokens can be used as a secret key in any project, Django, NodeJS, Golang, etc.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Securing web applications and software requires effective management of secret keys. Python offers libraries like cryptography and secrets that simplify the process of generating cryptographically secure tokens. To ensure maximum protection of sensitive data, it is crucial to store these keys securely using tools like Pypi Decouple and AWS Secrets Manager. By adhering to best practices for managing secret keys, developers can guarantee the security of their projects and prevent unauthorized access to sensitive information.</p>
<h1 id="heading-read-more">Read more</h1>
<ol>
<li><p><a target="_blank" href="https://cryptography.io/en/latest/hazmat/primitives/">Cryptography Algorithms - Primitives</a></p>
</li>
<li><p><a target="_blank" href="https://www.onelogin.com/learn/password-vaulting">Password Vaults</a></p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html">AWS Secrets Manager</a></p>
</li>
</ol>
<p>Follow me on Twitter <a target="_blank" href="https://twitter.com/netrobeweb">@netrobeweb</a>, <a target="_blank" href="https://hashnode.com/@netrobe">Hashnode</a>, and <a target="_blank" href="http://Dev.to">Dev.to</a> where I post amazing projects and articles.</p>
<p>Thanks for reading, 🤓😊</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681504977071/055d4a54-dc80-47b1-8cc2-e7efcc42cf1c.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[How to Build a Speech Authentication System with Django and Next JS - Part 1]]></title><description><![CDATA[Learn how to build a speech authentication system with Django in this comprehensive tutorial. With the help of a Python package that converts speech to text, users can enter their details by speaking. The system includes a registration and login page...]]></description><link>https://blog.covenlabs.space/how-to-build-a-speech-authentication-system-with-django-and-next-js-part-1</link><guid isPermaLink="true">https://blog.covenlabs.space/how-to-build-a-speech-authentication-system-with-django-and-next-js-part-1</guid><category><![CDATA[APIs]]></category><category><![CDATA[Django]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[speech to text]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Fri, 07 Apr 2023 21:02:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680900348299/96d733d9-a74f-4077-9e20-f60ffc5eb293.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Learn how to build a speech authentication system with Django in this comprehensive tutorial. With the help of a Python package that converts speech to text, users can enter their details by speaking. The system includes a registration and login page and once logged in, users will be greeted with a welcome voice. Follow the step-by-step guide to set up the backend API using Django and the frontend using Next.js and Chakra UI.</p>
<h3 id="heading-tldr">TL;DR</h3>
<p>The system includes a registration and login page and once logged in, users will be greeted with a welcome voice. Follow the step-by-step guide to set up the backend API using Django and the frontend using Next.js and Chakra UI. The article also covers the prerequisites, project setup, installations, and building of the API. The API includes endpoints for Registration, Login, JWT Token Refresh, User Retrieve, and Speech to Text.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Hey there! To make the most of this article, it would be helpful to have a solid understanding of <a target="_blank" href="https://docs.djangoproject.com/en/4.1/intro/tutorial01/">Django</a>, <a target="_blank" href="https://www.django-rest-framework.org/tutorial/quickstart/">Django Rest Framework</a>, and <a target="_blank" href="https://nextjs.org/docs/getting-started">Next.js</a>. Don't worry though, we'll do our best to explain things clearly and make it easy to follow along.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>First of all, we would work on the backend. Django will be used for the Backend and Next.js + Charkra UI for the front end. Django is used because we would be using a Python package that helps us convert speech to text.</p>
<h3 id="heading-application-design">Application Design</h3>
<p>The overall application design will be very simple. The backend will be an API which the frontend will consume.</p>
<ol>
<li><p>A user's voice will be recorded on the frontend.</p>
</li>
<li><p>The frontend sends the recorded wav file to the backend in <a target="_blank" href="https://en.wikipedia.org/wiki/Base64">Base64</a> format.</p>
</li>
<li><p>The backend will process the data and convert it to text.</p>
</li>
<li><p>The text is returned to the frontend as a response,</p>
</li>
<li><p>then text is entered into the UI input box.</p>
</li>
</ol>
<p>That's it, very simple.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>This project is already available on <a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth">GitHub</a>. Clone it and follow the installation guide in the <a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth#readme">Readme</a> to set up the project.</p>
<h3 id="heading-installations">Installations</h3>
<p>For building this project, we will need to have the following installed;</p>
<ul>
<li><p><a target="_blank" href="https://www.python.org/downloads/">Python 3.9</a> - This is used for the backend, and Django is used as the framework.</p>
</li>
<li><p><a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">NodeJs &amp; NPM</a> - This is used for the frontend.</p>
</li>
</ul>
<h2 id="heading-building-the-api">Building the API</h2>
<p>Let's clone the project.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/devvspaces/speech_to_text_auth
<span class="hljs-built_in">cd</span> speech_to_text_auth
</code></pre>
<p>For now, we would be working on the API. Move into the <code>api</code> directory.</p>
<p><strong>Set up your virtual environment</strong></p>
<pre><code class="lang-bash">python -m venv venv
<span class="hljs-comment"># Or python3 if you have that installed</span>
python3 -m venv venv
</code></pre>
<p>Check out this <a target="_blank" href="https://docs.python.org/3/library/venv.html">python documentation</a> to learn about virtual environments.</p>
<p><strong>Activate the environment.</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># windows: cmd.exe</span>
venv\Scripts\activate

<span class="hljs-comment"># bash or zsh</span>
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<p>If the above commands don't work, check out this <a target="_blank" href="https://docs.python.org/3/library/venv.html">python documentation</a> for help activating virtual environments. If you encounter an issue activating your virtual environment, here is a <a target="_blank" href="https://docs.python.org/3/library/venv.html#how-venvs-work">list of commands for common shells</a>.</p>
<p><strong>Installing requirements</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># This will install the requirements in the requirements.txt file</span>
pip install -r requirements.txt
</code></pre>
<p>Move into the <code>src</code> directory. There we have the account application, config, tests, and utils directories.</p>
<p>Now we need to create our <code>.env</code> file. This is where our secret configurations are kept. <a target="_blank" href="https://pypi.org/project/python-decouple/">Decouple</a> is used for accessing this file in our config files e.g <code>manage.py</code>, <code>wsgi.py</code>, etc.</p>
<p>Create a new file, <code>.env</code> and copy the contents of <code>.env.example</code> into it.</p>
<p>Now we need to create a Postgres DB for our project. By default, the project uses PostgreSQL but can be changed in the settings file. We can also create a DB for tests if we want to run tests. It's customary to have a separate database for development and testing because well testing uses autogenerated data which we don't want in our development database.</p>
<p>The config folder is where our settings are located. This directory contains a settings directory which contains two Python files, <code>base.py</code> and <code>test.py</code>. Having our settings file arranged like this helps us to write separate settings for different environments.</p>
<p>We could</p>
<ul>
<li><p>develop using the <code>base.py</code>,</p>
</li>
<li><p>test using the <code>test.py</code>,</p>
</li>
<li><p>maybe create a file <code>staging.py</code> for our staging environment in a live server</p>
</li>
<li><p>and <code>production.py</code> for our production environment.</p>
</li>
</ul>
<p>The tests folder contains our tests.</p>
<h3 id="heading-accounts-application">Accounts Application</h3>
<p>This is the only application on the project and the most important because we will store users' data here. The API views, models, and serializers are designed here.</p>
<p><a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/models.py"><strong>models.py</strong></a></p>
<p>This is a basic Django custom user <a target="_blank" href="https://docs.djangoproject.com/en/4.1/topics/db/models/">model</a> implementation. By inheriting the Django AbstractBaseUser model, we can build our User model and make email required.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680898951819/ef93ab84-3dd3-4edd-b349-84b24c7deca3.png" alt class="image--center mx-auto" /></p>
<p>This is the DBML structure used for the diagram above.</p>
<pre><code class="lang-sql">// <span class="hljs-keyword">Use</span> DBML <span class="hljs-keyword">to</span> <span class="hljs-keyword">define</span> your <span class="hljs-keyword">database</span> structure
// Docs: https://www.dbml.org/docs
// DB Diagram tool: https://dbdiagram.io/home

<span class="hljs-keyword">Table</span> <span class="hljs-keyword">users</span> {
  pk <span class="hljs-built_in">integer</span> [primary <span class="hljs-keyword">key</span>]
  email <span class="hljs-built_in">varchar</span>
  active <span class="hljs-built_in">boolean</span>
  staff <span class="hljs-built_in">boolean</span>
  <span class="hljs-keyword">admin</span> <span class="hljs-built_in">boolean</span>
  created <span class="hljs-built_in">timestamp</span>
}

<span class="hljs-keyword">Table</span> profile {
  pk <span class="hljs-built_in">integer</span> [primary <span class="hljs-keyword">key</span>]
  user_id <span class="hljs-built_in">integer</span>
  fullname <span class="hljs-built_in">varchar</span>
  sex <span class="hljs-built_in">varchar</span>
  phone <span class="hljs-built_in">varchar</span>
  country <span class="hljs-built_in">varchar</span>
}

<span class="hljs-keyword">Ref</span>: profile.user_id - users.pk // one-<span class="hljs-keyword">to</span>-one
</code></pre>
<p>The User model has a <a target="_blank" href="https://docs.djangoproject.com/en/4.2/topics/db/examples/one_to_one/">one-to-one relationship</a> with the Profile model. This is a very common way to design a User table. The reason for this is to make sure that when there is a change in business logic that will slightly affect how the User is created. We will update the Profile model instead so that we won't have migration issues with the User model.</p>
<p>When a user is created, we automatically create its profile by listening to the <code>post_save</code> signal. Learn more about <a target="_blank" href="https://docs.djangoproject.com/en/4.1/topics/signals/">Django Signals</a>.</p>
<p><a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/forms.py"><strong>forms.py</strong></a></p>
<p>We need a custom user registration form because we need a way to make the Django admin create a User correctly. This form allows the admin to enter the user's profile data when creating the user. The default Django admin form will have only fields for the User model.</p>
<p>By overriding the model form <a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/forms.py#:~:text=def%20save(self%2C%20commit%3DTrue)%3A">save method</a>, we get the validated profile data and populate the already created user profile. As soon as the <code>user.save()</code> is invoked, the profile will be created by the <code>post_save</code> signal from earlier.</p>
<p>Learn more about creating <a target="_blank" href="https://docs.djangoproject.com/en/4.1/topics/forms/modelforms/">Django Model Form</a>.</p>
<p><a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/admin.py"><strong>admin.py</strong></a></p>
<p>One important thing here is, we create a UserAdmin class for overriding the default that will be created by Django. Read more about <a target="_blank" href="https://docs.djangoproject.com/en/4.1/ref/contrib/admin/">Customizing Django Model Admin</a>.</p>
<p>Django <code>BaseUserAdmin</code> is a special ModelAdmin that allows us to override the form used for creating a new User instance in the admin. So we pass the form we created earlier here.</p>
<p><a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/config/settings/base.py"><strong>config/settings/base.py</strong></a></p>
<p>An important thing to note here is that after creating a Custom Django User Model we need to tell Django we want to use it instead of the default.</p>
<p>The line below tells Django to use our new Custom User Model instead of its default User Model. This is a very common implementation in Django, here is a <a target="_blank" href="https://github.com/devvspaces/django-restframework-template">Django Rest Framework GitHub template</a> that we can use as a project boilerplate.</p>
<pre><code class="lang-python">AUTH_USER_MODEL = <span class="hljs-string">'account.User'</span>
</code></pre>
<p>Decouple is used to access your environment keys, <code>.env</code>. This <a target="_blank" href="https://pypi.org/project/python-decouple/#example-how-do-i-use-it-with-django">documentation</a> shares how to effectively use decouple with Django.</p>
<p><a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/api/base/views.py"><strong>Views</strong></a> <strong>and</strong> <a target="_blank" href="https://github.com/devvspaces/speech_to_text_auth/blob/master/api/src/account/api/base/serializers.py"><strong>Serializers</strong></a></p>
<p>Now we will cover the Django rest framework views and serializers. We need the following endpoints;</p>
<ol>
<li><p>Registration [POST],</p>
</li>
<li><p>Login [POST],</p>
</li>
<li><p>JWT Token Refresh [POST],</p>
</li>
<li><p>User Retrieve [GET], and</p>
</li>
<li><p>Speech to Text [POST].</p>
</li>
</ol>
<p><strong>Registration [POST]</strong>: The endpoint will be used to create a new user. The data that will be received through all the endpoints will be in JSON format. The endpoint uses the imported RegisterSerializer to convert post data into native Python datatypes and validate them. An important thing to note here is that we are using <a target="_blank" href="https://jwt.io/introduction">JSON Web Token (JWT)</a> for authenticating our users. As soon as a new account is created, new access and refresh tokens are included in the response. Read more about <a target="_blank" href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/">Simple JWT</a>, A JSON Web Token authentication plugin for the Django REST Framework.</p>
<p><strong>Login [POST]</strong>: Validates the user data and returns a response that contains the tokens and logged-in user data.</p>
<p><strong>JWT Token Refresh [POST]</strong>: This is used to get a new access token using a valid refresh token. As JWT is a stateless authentication method, meaning there is no session stored for the user. Every 5 mins the access token previously generated is expired which requires the user to generate a new access token using the refresh token which is valid for 24 hours. The validation time for both the access and refresh tokens can be edited from the settings.py file. Learn more about this at <a target="_blank" href="https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html#access-token-lifetime">Simple JWT</a>.</p>
<p><strong>User Retrieve [GET]</strong>: We need to be able to get the data of the currently authenticated user. This endpoint returns the data of the authenticated user.</p>
<p><strong>Speech to Text [POST]</strong>: This endpoint used the <a target="_blank" href="https://pypi.org/project/SpeechRecognition/">SpeechRecognition package</a>, to convert audio binary to text. This package supports Google, IBM, and Microsoft Speech-to-text APIs and many more. Here we are using Google Speech-to-text. Because of the abstraction, the package brings, we don't need to call any actual API to upload our audio files for processing.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpeechToTextView</span>(<span class="hljs-params">APIView</span>):</span>

<span class="hljs-meta">    @swagger_auto_schema(</span>
        request_body=serializers.SpeechBody,
    )
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span>(<span class="hljs-params">self, request, *args, **kwargs</span>):</span>
        <span class="hljs-string">"""
        Convert speech to text, using Google Speech Recognition API
        Accepts a base64 encoded string of audio data
        Returns:
            Response: Response object with text
        """</span>
        <span class="hljs-keyword">try</span>:
            record: str = self.request.data.get(<span class="hljs-string">'record'</span>)
            decoded_b64 = base64.b64decode(record)

            <span class="hljs-comment"># Convert decoded_b64 to in-memory bytes buffer</span>
            r = sr.Recognizer()
            <span class="hljs-keyword">with</span> sr.AudioFile(io.BytesIO(decoded_b64)) <span class="hljs-keyword">as</span> source:
                <span class="hljs-comment"># listen for the data (load audio to memory)</span>
                audio_data = r.record(source)
                <span class="hljs-comment"># recognize (convert from speech to text)</span>
                text = r.recognize_google(audio_data)

            <span class="hljs-keyword">return</span> Response(data={<span class="hljs-string">'text'</span>: text})
        <span class="hljs-keyword">except</span> Exception:
            <span class="hljs-keyword">return</span> Response(
                data={<span class="hljs-string">'message'</span>: <span class="hljs-string">"Error converting speech to text"</span>},
                status=status.HTTP_400_BAD_REQUEST)
</code></pre>
<p>The data that will be passed to this endpoint will be in base64 format because it's faster and easier to transfer and process in this form.</p>
<pre><code class="lang-python">decoded_b64 = base64.b64decode(record)
</code></pre>
<p>This takes the data received and decodes it using the built-in <a target="_blank" href="https://docs.python.org/3/library/base64.html">base64</a> library. The decoded data returned is in binary form. This is done so that we can convert it into a <a target="_blank" href="https://docs.python.org/3/library/io.html#buffered-streams">Buffered stream</a> in memory using <code>io.BytesIO(decoded_b64)</code> , the built-in <code>io</code> library which is used for working with Input and Output (I/O) streams.</p>
<p><strong>What are Buffered I/O streams in Python?</strong></p>
<p>Buffered I/O streams in Python's <a target="_blank" href="https://docs.python.org/3/library/io.html"><code>io</code> module</a> are classes that help improve the performance of I/O operations by buffering data in memory. Think of buffering as a way of temporarily storing data in a queue so that it can be accessed more efficiently later on. <a target="_blank" href="https://medium.com/dev-bits/ultimate-guide-for-working-with-i-o-streams-and-zip-archives-in-python-3-6f3cf96dca50">Read more</a> on Buffered streams to deeply understand how it works.</p>
<p>When working with objects like Buffers, Files, or Database connections in Python <a target="_blank" href="https://realpython.com/python-with-statement/">Context Managers</a> are used to gain access to these objects because the connection is closed automatically even if there is an unhandled exception in the context manager.</p>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> sr.AudioFile(io.BytesIO(decoded_b64)) <span class="hljs-keyword">as</span> source:
    <span class="hljs-comment"># listen for the data (load audio to memory)</span>
    audio_data = r.record(source)
    <span class="hljs-comment"># recognize (convert from speech to text)</span>
    text = r.recognize_google(audio_data)
</code></pre>
<p>If an error occurs while trying to record the audio source, which is the Buffer we created earlier in the memory, the I/O connection will be closed safely. This <a target="_blank" href="https://towardsdatascience.com/why-you-should-use-context-managers-in-python-4f10fe231206#:~:text=What%20is%20a%20Context%20Manager,we%20are%20done%20with%20it.">article explains why it's important to use Context Managers</a> when dealing with objects like this.</p>
<p>So the buffer is recorded and passed to google for speech-to-text processing. If all is well, we return the text in the response else we raise a BadRequest error.</p>
<h2 id="heading-conclusion">Conclusion 🤓</h2>
<p>In conclusion, this article provides a comprehensive tutorial on how to build a speech authentication system with Django. The system allows users to enter their details by speaking and includes a registration and login page. The article covers the step-by-step guide to setting up the backend API using Django. The article also covers the necessary installations, project setup, and the design of the application. Overall, this article is a great resource for developers looking to build a speech authentication system.</p>
<p>To make this article brief the next part which is Building the Frontend with Next.js will be covered in another article.</p>
<p>You can follow me on <a target="_blank" href="https://twitter.com/netrobeweb">Twitter</a>, <a target="_blank" href="https://hashnode.com/@netrobe">Hashnode</a>, <a target="_blank" href="https://dev.to/devvspaces">Dev.to</a>, and <a target="_blank" href="http://github.com/devvspaces">Github</a>, where I post amazing projects and articles.</p>
<p>Thanks for reading, 😉.</p>
]]></content:encoded></item><item><title><![CDATA[Streamline Your File Uploads with Cloudinary and NestJS]]></title><description><![CDATA[Cloudinary is a powerful serverless cloud-based storage infrastructure that allows easy file uploading for NestJS projects. In this article, we will explore the various methods of file uploading to Cloudinary and how to set it up in your NestJS proje...]]></description><link>https://blog.covenlabs.space/streamline-your-file-uploads-with-cloudinary-and-nestjs</link><guid isPermaLink="true">https://blog.covenlabs.space/streamline-your-file-uploads-with-cloudinary-and-nestjs</guid><category><![CDATA[nestjs]]></category><category><![CDATA[cloudinary]]></category><category><![CDATA[File Upload]]></category><category><![CDATA[serverless]]></category><category><![CDATA[Base64]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Thu, 23 Mar 2023 10:06:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679565949785/a8a106ae-e262-4889-af79-20917851bf46.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cloudinary is a powerful serverless cloud-based storage infrastructure that allows easy file uploading for NestJS projects. In this article, we will explore the various methods of file uploading to Cloudinary and how to set it up in your NestJS project. Whether you are uploading file buffers, file URLs, or Base64 encoded strings, the Cloudinary NodeJS SDK and the steps outlined in this article make it easy to incorporate advanced file uploading into your NestJS project.</p>
<p>If you don't know how to handle file upload in NestJs, this <a target="_blank" href="https://thecodeway.hashnode.dev/mastering-file-upload-and-validation-in-nestjs-with-multer">article</a> explains how to efficiently incorporate file upload and validation into your NestJS project.</p>
<h2 id="heading-creating-a-cloudinary-module">Creating a Cloudinary Module</h2>
<p>One way to easily set it up in your NestJs projects is by creating a module for it. This allows you to use Dependency Injection design to use it in other providers or controllers.</p>
<p><strong>Installation</strong></p>
<p>Install Cloudinary NodeJs SDK</p>
<pre><code class="lang-bash">npm install cloudinary
</code></pre>
<p>Create a new module, <code>cloudinary</code>.</p>
<p>Create file <code>constants.ts</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CLOUDINARY = <span class="hljs-string">'Cloudinary'</span>;
</code></pre>
<p>Add file <code>cloudinary.provider.ts</code>, paste the code below into the file.</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
<span class="hljs-keyword">import</span> { v2 } <span class="hljs-keyword">from</span> <span class="hljs-string">'cloudinary'</span>;
<span class="hljs-keyword">import</span> { CLOUDINARY } <span class="hljs-keyword">from</span> <span class="hljs-string">'./constants'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CloudinaryProvider = {
  provide: CLOUDINARY,
  useFactory: <span class="hljs-function">(<span class="hljs-params">config: ConfigService</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> v2.config({
      cloud_name: config.get(<span class="hljs-string">'CLOUDINARY_CLOUD_NAME'</span>),
      api_key: config.get(<span class="hljs-string">'CLOUDINARY_API_KEY'</span>),
      api_secret: config.get(<span class="hljs-string">'CLOUDINARY_API_SECRET'</span>),
    });
  },
  inject: [ConfigService],
};
</code></pre>
<p><a target="_blank" href="https://docs.nestjs.com/techniques/configuration">ConfigService</a> is used to assess keys in your secret file. For example, a <code>.env</code> file.</p>
<p>Don't know how to set up env configurations in NestJs? <a target="_blank" href="https://docs.nestjs.com/techniques/configuration">Read more</a>.</p>
<p>Don't know how to create factory providers in NestJs? <a target="_blank" href="https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory">Read more</a>.</p>
<p>The <code>CloudinaryProvider</code> provider is a Factory Provider. The <code>useFactory</code> allows you to create providers dynamically. You can also inject other module-imported services into the <code>useFactory</code> function.</p>
<p><strong>Create the Cloudinary Service Injectable</strong></p>
<p>Add a new file, <code>cloudinary.service.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;


<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CloudinaryService {   
}
</code></pre>
<p>This service will contain methods for uploading files to Cloudinary.</p>
<p><strong>Create the module file</strong></p>
<p>Add a new file, <code>cloudinary.module.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
<span class="hljs-keyword">import</span> { CloudinaryProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cloudinary.provider'</span>;
<span class="hljs-keyword">import</span> { CloudinaryService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cloudinary.service'</span>;

<span class="hljs-meta">@Module</span>({
    imports: [ConfigModule],
    providers: [CloudinaryProvider, CloudinaryService],
    <span class="hljs-built_in">exports</span>: [CloudinaryProvider, CloudinaryService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CloudinaryModule {}
</code></pre>
<p>The <code>ConfigModule</code> is added to the module imports because <code>ConfigService</code> in the <code>CloudinaryProvider</code>.</p>
<p><strong>Setup .env file</strong></p>
<p>Create a <code>.env</code> in your root folder. Depending on how you structure your project, a general root folder could be the folder containing your <code>package.json</code> file or where you run the command to start your server.</p>
<pre><code class="lang-plaintext">CLOUDINARY_CLOUD_NAME=test
CLOUDINARY_API_KEY=test
CLOUDINARY_API_SECRET=test
</code></pre>
<p>Now you need to <a target="_blank" href="https://cloudinary.com/documentation/how_to_integrate_cloudinary">create a free Cloudinary account</a>. After creating your account, you can follow this <a target="_blank" href="https://cloudinary.com/documentation/how_to_integrate_cloudinary#:~:text=during%20Q1%202023.-,Product%20Environment%20Credentials,-The%20Product%20Environment">guide</a> to get your API key, secret and cloud name.</p>
<p><strong>Setup ConfigModule</strong></p>
<p>In your <code>app.module.ts</code> you will need to configure the <code>ConfigModule</code>. This makes sure it finds the <code>.env</code> file and populate itself with the keys and values, thereby making you access them with <code>ConfigService</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
  Module,
  NestModule,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [
    ConfigModule.forRoot(),
  ],
  controllers: [AppController],
  providers: [
    AppService,
  ],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule <span class="hljs-keyword">implements</span> NestModule {
}
</code></pre>
<h2 id="heading-using-form-data-file-buffers">Using Form data - File Buffers</h2>
<h3 id="heading-single-file-upload">Single File Upload</h3>
<p>Now that you have your <code>CloudinaryService</code>. When you create a route that <a target="_blank" href="https://thecodeway.hashnode.dev/mastering-file-upload-and-validation-in-nestjs-with-multer#heading-accepting-files">accepts file buffers</a> using Multer. You can upload this file using the service. You just have to integrate the upload method from the Cloudinary package.</p>
<p>Add the method below to your service.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> uploadFile(
  file: Express.Multer.File,
): <span class="hljs-built_in">Promise</span>&lt;UploadApiResponse | UploadApiErrorResponse&gt; {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    v2.uploader.upload_stream(
      {
        resource_type: <span class="hljs-string">'auto'</span>,
      },
      <span class="hljs-function">(<span class="hljs-params">error, result</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> reject(error);
        resolve(result);
      }
    ).end(file.buffer)
  })
}
</code></pre>
<p>This simple method uses <code>v2.uploader.upload_stream</code> to upload your file to Cloudinary in chunks, which is good for uploading large files in chunks instead of one long request.</p>
<p>An <code>UploadApiResponse</code> or <code>UploadApiErrorResponse</code> is returned by the function. You can use this to know if the file was successfully uploaded or not.</p>
<p>To access your uploaded file URL, use the example of a route for single file upload below to understand the process.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { UploadedFile, UseInterceptors } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;

<span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload/single'</span>)
<span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>))
<span class="hljs-meta">@ApiOkResponse</span>({ description: <span class="hljs-string">'Upload image'</span>, <span class="hljs-keyword">type</span>: <span class="hljs-built_in">String</span> })
<span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> uploadSingleImage(<span class="hljs-meta">@UploadedFile</span>() file: Express.Multer.File) {
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.cloudinaryService.uploadFile(file);
  <span class="hljs-keyword">return</span> result.secure_url;
}
</code></pre>
<p>The <code>secure_url</code> property is the URL for the file uploaded.</p>
<h3 id="heading-uploading-multiple-file-buffers">Uploading multiple file buffers</h3>
<p>Loop through all the files and upload each one after the other. The response is the list of secure URLs.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> uploadFiles(
  files: Express.Multer.File[],
) {
  <span class="hljs-keyword">const</span> urls = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(files.map(<span class="hljs-keyword">async</span> (file): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; =&gt; {
    <span class="hljs-keyword">const</span> { secure_url } = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.uploadFile(file);
    <span class="hljs-keyword">return</span> secure_url;
  }));
  <span class="hljs-keyword">return</span> urls
}
</code></pre>
<p>The files were <a target="_blank" href="https://www.w3schools.com/jsref/jsref_map.asp">mapped over</a> and uploaded, and their URLs were returned by the <a target="_blank" href="https://www.w3schools.com/jsref/jsref_map.asp">map callback function</a>.</p>
<h2 id="heading-uploading-file-with-urls">Uploading File with URLs</h2>
<p>What if you have a file URL and not a file buffer? It's simpler to upload that using Cloudinary.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> uploadFileFromUrl(
  url: <span class="hljs-built_in">string</span>,
): <span class="hljs-built_in">Promise</span>&lt;UploadApiResponse | UploadApiErrorResponse&gt; {
  <span class="hljs-keyword">return</span> v2.uploader.upload(url)
}
</code></pre>
<p>The URL passed to this would be uploaded to Cloudinary, which will then return a response containing the <code>secure_url</code> if successful.</p>
<h3 id="heading-uploading-multiple-file-urls">Uploading multiple file urls</h3>
<p>By following the same idea from uploading multiple file buffers. You can map through the urls, upload each and return the <code>secure_url</code> for each. Then the function will return a list of URLs.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> uploadFilesFromUrl(
  urls: <span class="hljs-built_in">string</span>[],
) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.all(urls.map(<span class="hljs-keyword">async</span> (url: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; =&gt; {
    <span class="hljs-keyword">const</span> { secure_url } = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.uploadFileFromUrl(url);
    <span class="hljs-keyword">return</span> secure_url;
  }));
}
</code></pre>
<h2 id="heading-uploading-base64-encoded-strings">Uploading Base64 encoded strings</h2>
<p>Base64 is a binary-to-text encoding scheme that represents binary data in an American Standard Code for Information Interchange (ASCII) string format. An example of binary data is an image. Base64 can be uploaded too as a file, it's a string and not a buffer, which makes it easier to parse and upload to Cloudinary than file buffers.</p>
<p>By utilizing the <code>upload</code> function from the Cloudinary package, a base64 string can be uploaded to Cloudinary and get a URL for the uploaded file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> uploadFileFromBase64(
  data: <span class="hljs-built_in">string</span>,
): <span class="hljs-built_in">Promise</span>&lt;UploadApiResponse | UploadApiErrorResponse&gt; {
  <span class="hljs-keyword">return</span> v2.uploader.upload(data)
}

<span class="hljs-keyword">async</span> uploadManyBase64(
  files: <span class="hljs-built_in">string</span>[],
) {
  <span class="hljs-keyword">const</span> urls = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(files.map(<span class="hljs-keyword">async</span> (file): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; =&gt; {
    <span class="hljs-keyword">const</span> { secure_url } = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.uploadFileFromBase64(file);
    <span class="hljs-keyword">return</span> secure_url;
  }));
  <span class="hljs-keyword">return</span> urls
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Cloudinary is a powerful tool for file uploading and storage in NestJS projects. With the help of the Cloudinary NodeJS SDK and the steps outlined in this article, developers can easily set up a module for Cloudinary and upload files using various available methods including file buffers, file URLs, and Base64 encoded strings. While Cloudinary is free to set up initially, developers may need to pay for used services once they start using it past some limit.</p>
<p>I'd love to connect ❤️ with you on <a target="_blank" href="https://twitter.com/netrobeweb"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/ayomide-ayanwola/"><strong>LinkedIn</strong></a> | <a target="_blank" href="http://github.com/devvspaces"><strong>GitHub</strong></a> | <a target="_blank" href="https://netrobe.vercel.app/"><strong>Portfolio</strong></a></p>
<p>See you in my next blog article. Take care!!!</p>
]]></content:encoded></item><item><title><![CDATA[Creating Admin Panels for NestJs and Prisma Made Easy with AdminJS]]></title><description><![CDATA[If you find yourself investing considerable time in building admin panels for NestJs and Prisma applications, AdminJS can be the solution. AdminJS is a robust framework that facilitates the creation of a comprehensive admin dashboard with minimal cod...]]></description><link>https://blog.covenlabs.space/creating-admin-panels-for-nestjs-and-prisma-made-easy-with-adminjs</link><guid isPermaLink="true">https://blog.covenlabs.space/creating-admin-panels-for-nestjs-and-prisma-made-easy-with-adminjs</guid><category><![CDATA[nestjs]]></category><category><![CDATA[prisma]]></category><category><![CDATA[orm]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[AdminJS ]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Tue, 21 Mar 2023 12:52:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679402031888/9d03333a-b47c-49c0-8fe0-ae8ea13424b4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you find yourself investing considerable time in building admin panels for NestJs and Prisma applications, AdminJS can be the solution. AdminJS is a robust framework that facilitates the creation of a comprehensive admin dashboard with minimal coding. It is compatible with numerous ORM and ODM models, streamlining CRUD operations on your models.</p>
<p>Moreover, AdminJS offers customization options that enable you to personalize the dashboard according to your project requirements. Kindly read further to acquire guidance on initiating AdminJS and attaining mastery over your application's data management.</p>
<h3 id="heading-what-is-orm">What is ORM</h3>
<p>Object-relational mapping (ORM) in computer science is a programming technique for converting data between incompatible type systems using object-oriented programming languages.</p>
<h3 id="heading-what-is-odm">What is ODM?</h3>
<p>Object Document Mapper (ODM) is a library that helps you to work with MongoDB databases. It provides an abstraction layer between the database and the application code. It allows you to use the object-oriented paradigm to work with the database.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p><strong>AdminJs + NestJs =&gt; AdminJs + Prisma =&gt; Customizations</strong></p>
<p>The aforementioned flow provides a concise overview of the process involved in configuring AdminJs for your NestJs project.</p>
<p>The recommended approach entails commencing the process by installing the requisite AdminJs packages. Subsequently, configure AdminJs with NestJs followed by Prisma, and finally, incorporate customizations as necessary which is optional.</p>
<p><strong>Install Requirements</strong></p>
<p>It's required that you have your nest project already set up, if you don't know how to create one you can use the official NestJs documentation.</p>
<pre><code class="lang-bash">yarn add adminjs @adminjs/nestjs @adminjs/express express-session express-formidable
</code></pre>
<p>All the requirements above are required by AdminJs and more information on them can be provided by AdminJs Docs.</p>
<p><strong>app.module.ts</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>
<span class="hljs-keyword">import</span> { AdminModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@adminjs/nestjs'</span>

<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>

<span class="hljs-keyword">const</span> DEFAULT_ADMIN = {
  email: <span class="hljs-string">'admin@example.com'</span>,
  password: <span class="hljs-string">'password'</span>,
}

<span class="hljs-keyword">const</span> authenticate = <span class="hljs-keyword">async</span> (email: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">if</span> (email === DEFAULT_ADMIN.email &amp;&amp; password === DEFAULT_ADMIN.password) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(DEFAULT_ADMIN)
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
}

<span class="hljs-meta">@Module</span>({
  imports: [
    AdminModule.createAdminAsync({
      useFactory: <span class="hljs-function">() =&gt;</span> ({
        adminJsOptions: {
          rootPath: <span class="hljs-string">'/admin'</span>,
          resources: [],
        },
        auth: {
          authenticate,
          cookieName: <span class="hljs-string">'adminjs'</span>,
          cookiePassword: <span class="hljs-string">'secret'</span>
        },
        sessionOptions: {
          resave: <span class="hljs-literal">true</span>,
          saveUninitialized: <span class="hljs-literal">true</span>,
          secret: <span class="hljs-string">'secret'</span>
        },
      }),
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>You might want your admin panel to not require authentication depending on the project you are working on. By removing the <code>auth</code> and <code>sessionOptions</code> from the object returned by the <a target="_blank" href="https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory">factory provider</a>.</p>
<p><strong>app.module.ts</strong></p>
<pre><code class="lang-typescript">...
AdminModule.createAdminAsync({
  useFactory: <span class="hljs-function">() =&gt;</span> ({
    adminJsOptions: {
      rootPath: <span class="hljs-string">'/admin'</span>,
      resources: [],
    },
  }),
}),
...
</code></pre>
<p>The upper part and lower part of the <strong>app.module.ts</strong> is removed to conserve space.</p>
<p><strong>Start your server</strong></p>
<pre><code class="lang-bash">nest start --watch
<span class="hljs-comment"># OR</span>
nest start
</code></pre>
<p>Visit <code>127.0.0.1:&lt;your port&gt;/admin</code> . If you have authentication enabled it will automatically redirect you to the login page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679400981499/d788bc7f-0dd7-4bbd-ae25-38f593fcf18f.png" alt class="image--center mx-auto" /></p>
<p>Enter the details from the <code>DEFAULT_ADMIN</code> object in the <code>app.module.ts</code> program.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679401202328/655870a7-27bf-42da-9e08-595796e20766.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-using-adapters-to-connect-to-the-database-in-adminjs">Using Adapters to Connect to the Database in AdminJS</h2>
<p>This tutorial focuses on using Prisma as the ORM. <a target="_blank" href="https://www.prisma.io/docs/concepts/overview/what-is-prisma">Prisma</a> is open-source, has an auto-generated type-safe client for Node.js &amp; Typescript, and manages migrations. AdminJs also work with other ORMs e.g TypeORM etc. They are called <a target="_blank" href="https://docs.adminjs.co/installation/adapters">adapters</a> and you can choose what you want to use. If you want to learn Prisma, follow this guide to <a target="_blank" href="https://www.prisma.io/docs/getting-started">getting started</a> with Prisma ORM.</p>
<p>If you can't find your models on the dashboard after logging in, this is because AdminJs uses adapters you defined to connect to the database. It uses it as an intermediary to perform database actions like querying, creating, updating, etc.</p>
<p><strong>schema.prisma</strong></p>
<pre><code class="lang-typescript">generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}

model User {
  pk            Int      <span class="hljs-meta">@id</span> <span class="hljs-meta">@default</span>(autoincrement())
  id            <span class="hljs-built_in">String</span>   <span class="hljs-meta">@unique</span> <span class="hljs-meta">@default</span>(uuid()) <span class="hljs-meta">@db</span>.Uuid
  email         <span class="hljs-built_in">String</span>   <span class="hljs-meta">@unique</span>
  password      <span class="hljs-built_in">String</span>
  active        <span class="hljs-built_in">Boolean</span>  <span class="hljs-meta">@default</span>(<span class="hljs-literal">true</span>)
  staff         <span class="hljs-built_in">Boolean</span>  <span class="hljs-meta">@default</span>(<span class="hljs-literal">false</span>)
  admin         <span class="hljs-built_in">Boolean</span>  <span class="hljs-meta">@default</span>(<span class="hljs-literal">false</span>)
  profile       Profile?

  @<span class="hljs-meta">@unique</span>([pk, id])
  @<span class="hljs-meta">@map</span>(<span class="hljs-string">"users"</span>)
}

model Profile {
  pk              Int                      <span class="hljs-meta">@id</span> <span class="hljs-meta">@default</span>(autoincrement())
  id              <span class="hljs-built_in">String</span>                   <span class="hljs-meta">@unique</span> <span class="hljs-meta">@default</span>(uuid()) <span class="hljs-meta">@db</span>.Uuid
  firstName       <span class="hljs-built_in">String</span>?                  <span class="hljs-meta">@map</span>(<span class="hljs-string">"first_name"</span>)
  lastName        <span class="hljs-built_in">String</span>?                  <span class="hljs-meta">@map</span>(<span class="hljs-string">"last_name"</span>)
  userPk          Int                      <span class="hljs-meta">@unique</span> <span class="hljs-meta">@map</span>(<span class="hljs-string">"user_pk"</span>)
  userId          <span class="hljs-built_in">String</span>                   <span class="hljs-meta">@unique</span> <span class="hljs-meta">@map</span>(<span class="hljs-string">"user_id"</span>) <span class="hljs-meta">@db</span>.Uuid
  user            User                     <span class="hljs-meta">@relation</span>(fields: [userPk, userId], references: [pk, id], onDelete: Cascade, onUpdate: Cascade)

  @<span class="hljs-meta">@unique</span>([pk, id])
  @<span class="hljs-meta">@unique</span>([userPk, userId])
  @<span class="hljs-meta">@map</span>(<span class="hljs-string">"profiles"</span>)
}
</code></pre>
<p><strong>app.module.ts</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>
<span class="hljs-keyword">import</span> { AdminModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@adminjs/nestjs'</span>
<span class="hljs-keyword">import</span> { Database, Resource } <span class="hljs-keyword">from</span> <span class="hljs-string">'@adminjs/prisma'</span>;
<span class="hljs-keyword">import</span> AdminJS <span class="hljs-keyword">from</span> <span class="hljs-string">'adminjs'</span>
<span class="hljs-keyword">import</span> { DMMFClass } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client/runtime'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@database/prisma.service'</span>;
<span class="hljs-keyword">import</span> { DatabaseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@database/database.module'</span>;

<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>

<span class="hljs-keyword">const</span> DEFAULT_ADMIN = {
  email: <span class="hljs-string">'admin@example.com'</span>,
  password: <span class="hljs-string">'password'</span>,
}

<span class="hljs-keyword">const</span> authenticate = <span class="hljs-keyword">async</span> (email: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">if</span> (email === DEFAULT_ADMIN.email &amp;&amp; password === DEFAULT_ADMIN.password) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(DEFAULT_ADMIN)
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
}

AdminJS.registerAdapter({ Database, Resource });

<span class="hljs-meta">@Module</span>({
  imports: [
    AdminModule.createAdminAsync({
      imports: [DatabaseModule],
      useFactory: <span class="hljs-function">(<span class="hljs-params">prisma: PrismaService</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> dmmf = (prisma <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)._baseDmmf <span class="hljs-keyword">as</span> DMMFClass;

        <span class="hljs-keyword">return</span> {
          adminJsOptions: {
            rootPath: <span class="hljs-string">'/admin'</span>,
            resources: [
              {
                resource: { model: dmmf.modelMap[<span class="hljs-string">'User'</span>], client: prisma },
                options: {},
              },
              {
                resource: { model: dmmf.modelMap[<span class="hljs-string">'Profile'</span>], client: prisma },
                options: {},
              },
            ],
          },
          auth: {
            authenticate,
            cookieName: <span class="hljs-string">'adminjs'</span>,
            cookiePassword: <span class="hljs-string">'secret'</span>
          },
          sessionOptions: {
            resave: <span class="hljs-literal">true</span>,
            saveUninitialized: <span class="hljs-literal">true</span>,
            secret: <span class="hljs-string">'secret'</span>
          },
        }
      },
      inject: [PrismaService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>Explore the basic Resource object format and effortlessly add multiple resources to your project.</p>
<pre><code class="lang-typescript">{
  resource: { model: dmmf.modelMap[{Model name here}], client: prisma },
  options: {},
}
</code></pre>
<p>Make sure you replace <code>{Model name here}</code> with the name of the model you want to use. For example, if you have a model <code>Post</code>, you would replace <code>{Model name here}</code> with <code>Post</code>.</p>
<h4 id="heading-how-does-this-work">How does this work?</h4>
<p>The Database Model Mapper (DMMF) object comprises a comprehensive depiction of your database schema. Its functionality extends to facilitating the extraction of your model from Prisma. The DMMF achieves this by mapping model names to their respective model objects. For example, to retrieve the User model from the map, one can utilize the syntax <code>dmmf.modelMap['User']</code>. Once the model object is obtained, it can be assigned to the resource's model property.</p>
<p>The Prisma client serves as the client property, facilitating connectivity to the database for conducting CRUD operations.</p>
<p>You can add as many resources as you need. For example, if you have a <code>Post</code> model in your Prisma schema that you want to be displayed in the Admin Dashboard. You just need to add it to the resources array;</p>
<p><strong>app.module.ts</strong></p>
<pre><code class="lang-typescript">...
{
  resource: { model: dmmf.modelMap[<span class="hljs-string">'Post'</span>], client: prisma },
  options: {},
},
...
</code></pre>
<p>Now restart your server if it's not on fast reload.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679401266016/7121f311-b9c8-49fb-8d8e-38d2572414fe.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-simplify-adding-resources">Simplify adding resources</h3>
<p>When managing a substantial number of database models, it is common to encounter the need for duplicating codes while incorporating new resources for each model.</p>
<p>The implementation of the <a target="_blank" href="https://en.wikipedia.org/wiki/Builder_pattern#:~:text=The%20builder%20pattern%20is%20a,Gang%20of%20Four%20design%20patterns.">Builder pattern</a> in coding allows for the addition of multiple resources without duplicating code, thereby enhancing code efficiency and ease of maintenance. Consider incorporating this pattern into your coding practices to reap the benefits.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>
<span class="hljs-keyword">import</span> { AdminModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@adminjs/nestjs'</span>
<span class="hljs-keyword">import</span> { Database, Resource } <span class="hljs-keyword">from</span> <span class="hljs-string">'@adminjs/prisma'</span>;
<span class="hljs-keyword">import</span> AdminJS <span class="hljs-keyword">from</span> <span class="hljs-string">'adminjs'</span>
<span class="hljs-keyword">import</span> { DMMFClass } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client/runtime'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@database/prisma.service'</span>;
<span class="hljs-keyword">import</span> { DatabaseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@database/database.module'</span>;
<span class="hljs-keyword">import</span> { ResourceWithOptions, ResourceOptions } <span class="hljs-keyword">from</span> <span class="hljs-string">'adminjs/types/src'</span>;

<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>

<span class="hljs-keyword">const</span> DEFAULT_ADMIN = {
  email: <span class="hljs-string">'admin@example.com'</span>,
  password: <span class="hljs-string">'password'</span>,
}

<span class="hljs-keyword">const</span> authenticate = <span class="hljs-keyword">async</span> (email: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">if</span> (email === DEFAULT_ADMIN.email &amp;&amp; password === DEFAULT_ADMIN.password) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(DEFAULT_ADMIN)
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
}

AdminJS.registerAdapter({ Database, Resource });

<span class="hljs-keyword">class</span> CResource {
  model: <span class="hljs-built_in">any</span>;
  options: ResourceOptions;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">model: <span class="hljs-built_in">any</span>, options?: ResourceOptions</span>) {
    <span class="hljs-built_in">this</span>.model = model;
    <span class="hljs-built_in">this</span>.options = options || {};
  }
}

<span class="hljs-keyword">class</span> CResourceBuilder {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> resources: <span class="hljs-built_in">Array</span>&lt;CResource&gt; = [];
  dmmf: DMMFClass;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> prisma: PrismaService</span>) {
    <span class="hljs-built_in">this</span>.dmmf = ((prisma <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)._baseDmmf <span class="hljs-keyword">as</span> DMMFClass)
  }

  <span class="hljs-comment">/**
   * Adds a resource to the builder
   * 
   * @param resource string
   * @param options ResourceOptions
   * @returns this
   */</span>
  <span class="hljs-keyword">public</span> addResource(resource: <span class="hljs-built_in">string</span>, options?: ResourceOptions): <span class="hljs-built_in">this</span> {
    <span class="hljs-keyword">const</span> obj = <span class="hljs-keyword">new</span> CResource(<span class="hljs-built_in">this</span>.dmmf.modelMap[resource], options);
    <span class="hljs-built_in">this</span>.resources.push(obj);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }

  <span class="hljs-comment">/**
   * Compiles the resources into an array of objects
   * that can be passed to the AdminJS module
   * 
   * @returns Array&lt;ResourceWithOptions | any&gt;
   */</span>
  <span class="hljs-keyword">public</span> build(): <span class="hljs-built_in">Array</span>&lt;ResourceWithOptions | <span class="hljs-built_in">any</span>&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.resources.map(<span class="hljs-function">(<span class="hljs-params">resource</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> {
        resource: {
          model: resource.model,
          client: <span class="hljs-built_in">this</span>.prisma,
        },
        options: resource.options,
      }
    })
  }
}

<span class="hljs-meta">@Module</span>({
  imports: [
    AdminModule.createAdminAsync({
      imports: [DatabaseModule],
      useFactory: <span class="hljs-function">(<span class="hljs-params">prisma: PrismaService</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> dmmf = (prisma <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)._baseDmmf <span class="hljs-keyword">as</span> DMMFClass;

        <span class="hljs-keyword">return</span> {
          adminJsOptions: {
            rootPath: <span class="hljs-string">'/admin'</span>,

            <span class="hljs-comment">// updated here</span>
            resources: <span class="hljs-keyword">new</span> CResourceBuilder(prisma)
              .addResource(<span class="hljs-string">'User'</span>)
              .addResource(<span class="hljs-string">'Profile'</span>)
              .addResource(<span class="hljs-string">'Post'</span>)
              .build(),
          },
          auth: {
            authenticate,
            cookieName: <span class="hljs-string">'adminjs'</span>,
            cookiePassword: <span class="hljs-string">'secret'</span>
          },
          sessionOptions: {
            resave: <span class="hljs-literal">true</span>,
            saveUninitialized: <span class="hljs-literal">true</span>,
            secret: <span class="hljs-string">'secret'</span>
          },
        }
      },
      inject: [PrismaService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<blockquote>
<p>You can always export the classes, functions and objects from an external file.</p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, AdminJS is a powerful tool for creating admin dashboards for NestJS and Prisma applications. With its adapters for various ORM and ODM models, it simplifies the process of performing CRUD operations on models. It also provides customization options for the dashboard, making it easy to tailor it to specific project needs. By following the steps outlined in the article, developers can quickly set up AdminJS and start using it to manage their application's data.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://docs.adminjs.co/basics/resource">More options for resources</a></p>
</li>
<li><p><a target="_blank" href="https://docs.adminjs.co/ui-customization/writing-your-own-components">Customizing your Admin Dashboard</a></p>
</li>
</ul>
<p>I'd love to connect with you on <a target="_blank" href="https://twitter.com/netrobeweb"><strong>Twitter</strong></a> | <a target="_blank" href="https://www.linkedin.com/in/ayomide-ayanwola/"><strong>LinkedIn</strong></a> | <a target="_blank" href="http://github.com/devvspaces"><strong>GitHub</strong></a> | <a target="_blank" href="https://netrobe.vercel.app/"><strong>Portfolio</strong></a></p>
<p>See you in my next blog article. Take care!!!</p>
]]></content:encoded></item><item><title><![CDATA[Mastering File Upload and Validation in NestJS with Multer]]></title><description><![CDATA[This guide will show you how to efficiently incorporate file upload and validation into your NestJS project. The tutorial will walk you through the steps of receiving and verifying files using the Multer middleware package with the Express Adapter. B...]]></description><link>https://blog.covenlabs.space/mastering-file-upload-and-validation-in-nestjs-with-multer</link><guid isPermaLink="true">https://blog.covenlabs.space/mastering-file-upload-and-validation-in-nestjs-with-multer</guid><category><![CDATA[nestjs]]></category><category><![CDATA[multer]]></category><category><![CDATA[File Upload]]></category><category><![CDATA[Validation]]></category><category><![CDATA[Middleware]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sat, 18 Mar 2023 12:04:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679054576314/bb731ed7-bf84-4398-a48e-95e226440017.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This guide will show you how to efficiently incorporate file upload and validation into your NestJS project. The tutorial will walk you through the steps of receiving and verifying files using the Multer middleware package with the Express Adapter. By following this guide, you can create a personalized file upload and validation process that works best for your NestJS application.</p>
<h2 id="heading-accepting-files">Accepting files</h2>
<p>File processing in NestJs is handled with Multer. It has a built-in Multer middleware package for Express Adapter. The only required package to install is <code>@types/multer</code>, which is for better type safety.</p>
<pre><code class="lang-bash">npm i -D @types/multer @nestjs/platform-express
</code></pre>
<p>Start by creating an endpoint for single file uploads.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Post, UploadedFile, UseInterceptors, Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {
    <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
    <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>))
    uploadFile(<span class="hljs-meta">@UploadedFile</span>() file: Express.Multer.File) {
        <span class="hljs-built_in">console</span>.log(file);
    }
}
</code></pre>
<blockquote>
<p>Make sure to use <code>@nestjs/common: "^9.0.0"</code>, it's required to use <code>UploadedFile</code>.</p>
</blockquote>
<p>If you use swagger, you can specify <code>ApiConsumes</code> decorator to <code>multipart/form-data</code>. This tells swagger that this route accepts form data.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Post, UploadedFile, UseInterceptors, Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { ApiConsumes, ApiTags } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;

<span class="hljs-meta">@ApiTags</span>(<span class="hljs-string">'Uploding Files'</span>)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-meta">@ApiConsumes</span>(<span class="hljs-string">'multipart/form-data'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {
    <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
    <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>))
    uploadFile(<span class="hljs-meta">@UploadedFile</span>() file: Express.Multer.File) {
        <span class="hljs-built_in">console</span>.log(file);
    }
}
</code></pre>
<p>When it comes to filing storage, Multer has a default memory setting. While this is a viable choice, it may not suit your needs if you plan to bypass disk storage and instead upload files directly to external storage solutions like Cloudinary or AWS S3.</p>
<h3 id="heading-how-to-save-data-to-disk-storage">How to Save Data to Disk Storage</h3>
<p>To upload your files to disk storage, you can provide the file destination in the <code>FileInterceptor</code>. The interceptor accepts <a target="_blank" href="https://github.com/expressjs/multer#multeropts">Multer Options</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> UPLOAD_DIR = <span class="hljs-string">'./upload/files/'</span>;

<span class="hljs-meta">@ApiTags</span>(<span class="hljs-string">'Uploding Files'</span>)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-meta">@ApiConsumes</span>(<span class="hljs-string">'multipart/form-data'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {
    <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
    <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { dest: UPLOAD_DIR }))
    uploadFile(<span class="hljs-meta">@UploadedFile</span>() file: Express.Multer.File) {
        <span class="hljs-built_in">console</span>.log(file);
    }
}
</code></pre>
<p>The upload directory path is relative to your root directory.</p>
<p>Hey there! When dealing with a lot of users, we want to make sure we avoid any issues that might come up with file names. To prevent this from happening, we recommend assigning a separate folder for each upload. That way, everything stays organized and everyone can easily find what they need.</p>
<p>There is a helpful tip to share with you. Are you aware that every user can have their unique folder in the upload directory? What's more, you can enhance this feature by configuring a storage engine for Multer, which allows you to create a dynamic upload path. Why not give it a try?</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Post, UploadedFile, UseInterceptors, Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { ApiConsumes, ApiTags } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;
<span class="hljs-keyword">import</span> { Request } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> { diskStorage } <span class="hljs-keyword">from</span> <span class="hljs-string">'multer'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;

<span class="hljs-keyword">const</span> UPLOAD_DIR = <span class="hljs-string">'./upload/files/'</span>;

<span class="hljs-comment">// User interface of the authenticated user</span>
<span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">string</span>;
}

<span class="hljs-comment">/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */</span>
<span class="hljs-keyword">const</span> defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: <span class="hljs-function">(<span class="hljs-params">req: Request &amp; { user: User }, file, cb</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> uid = req.user.id;
    cb(<span class="hljs-literal">null</span>, <span class="hljs-string">`<span class="hljs-subst">${uid}</span><span class="hljs-subst">${path.extname(file.originalname)}</span>`</span>)
  }
})

<span class="hljs-meta">@ApiTags</span>(<span class="hljs-string">'Uploding Files'</span>)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-meta">@ApiConsumes</span>(<span class="hljs-string">'multipart/form-data'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
  <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
  uploadFile(<span class="hljs-meta">@UploadedFile</span>() file: Express.Multer.File) {
    <span class="hljs-built_in">console</span>.log(file);
  }

}
</code></pre>
<p>In this example, the user object could be attached to the request manually in the auth <a target="_blank" href="https://docs.nestjs.com/middleware">middleware</a>.</p>
<p>This is a perfect example of how to accept files and save them in a super cool and unique path!</p>
<blockquote>
<p>The file would be saved to disk before <code>console.log(file)</code> runs.</p>
</blockquote>
<p>The next section provides a way of adding file processing like validation of files uploaded.</p>
<h2 id="heading-validate-your-files-with-parsefilepipe-and-parsefilepipebuilder">Validate Your Files with ParseFilePipe and ParseFilePipeBuilder</h2>
<h3 id="heading-using-parsefilepipe-with-validator-classes">Using ParseFilePipe with Validator classes</h3>
<p>NestJs Pipes offer an efficient way to validate files. To perform file validation, simply create a validator class such as MaxFileSizeValidator or FileNameValidator, and pass it to the ParseFilePipe.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ..., ParseFilePipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

...

<span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
<span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
uploadFile(
  <span class="hljs-meta">@UploadedFile</span>(
    <span class="hljs-keyword">new</span> ParseFilePipe({
      validators: [
        <span class="hljs-comment">// ... Set of file validator instances here</span>
      ]
    })
  )
  file: Express.Multer.File
) {
  <span class="hljs-built_in">console</span>.log(file);
}

...
</code></pre>
<p>Create a <code>FileValidator</code> class to use with <code>ParseFilePipe</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { FileValidator } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-keyword">class</span> MaxFileSize <span class="hljs-keyword">extends</span> FileValidator&lt;{ maxSize: <span class="hljs-built_in">number</span> }&gt;{
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">options: { maxSize: <span class="hljs-built_in">number</span> }</span>) {
    <span class="hljs-built_in">super</span>(options)
  }

  isValid(file: Express.Multer.File): <span class="hljs-built_in">boolean</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt; {
    <span class="hljs-keyword">const</span> in_mb = file.size / <span class="hljs-number">1000000</span>
    <span class="hljs-keyword">return</span> in_mb &lt;= <span class="hljs-built_in">this</span>.validationOptions.maxSize
  }
  buildErrorMessage(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`File uploaded is too big. Max size is (<span class="hljs-subst">${<span class="hljs-built_in">this</span>.validationOptions.maxSize}</span> MB)`</span>
  }
}
</code></pre>
<p>The interface<code>FileValidator</code> has two methods needed to create its class. The method <code>isValid</code> and <code>buildErrorMessage</code>.</p>
<p>The method, <code>isValid</code> will contain your logic that defines if the file is valid or not depending on the options passed in the constructor.</p>
<p>From the constructor definition, <code>maxSize</code> can be passed as an option and is used in the <code>isValid</code> method to know what is considered the maximum file size.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Builds an error message in case the validation fails.
 * @param file the file from the request object
 */</span>
<span class="hljs-keyword">abstract</span> buildErrorMessage(file: <span class="hljs-built_in">any</span>): <span class="hljs-built_in">string</span>;
</code></pre>
<p>Above is the interface of the <code>buildErrorMessage</code> function. It's used to build unique or general error messages for uploaded files.</p>
<p>Pass an instance of the <code>MaxFileSize</code> class in the <code>ParseFilePipe</code>. The <code>maxSize</code> can be passed to the constructor during instantiation.</p>
<pre><code class="lang-typescript">...

<span class="hljs-keyword">const</span> MAX_UPLOAD_SIZE = <span class="hljs-number">10</span>; <span class="hljs-comment">// in MB</span>
...

<span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
<span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
uploadFile(
  <span class="hljs-meta">@UploadedFile</span>(
    <span class="hljs-keyword">new</span> ParseFilePipe({
      validators: [
        <span class="hljs-comment">// ... Set of file validator instances here</span>
        <span class="hljs-keyword">new</span> MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ]
    })
  )
  file: Express.Multer.File
) {
  <span class="hljs-built_in">console</span>.log(file);
}

...
</code></pre>
<p>The code should look like this now</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Post, UploadedFile, UseInterceptors, Controller, ParseFilePipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { ApiConsumes, ApiTags } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;
<span class="hljs-keyword">import</span> { Request } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> { diskStorage } <span class="hljs-keyword">from</span> <span class="hljs-string">'multer'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;
<span class="hljs-keyword">import</span> { FileValidator } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-keyword">const</span> UPLOAD_DIR = <span class="hljs-string">'./upload/files/'</span>;
<span class="hljs-keyword">const</span> MAX_UPLOAD_SIZE = <span class="hljs-number">10</span>; <span class="hljs-comment">// in MB</span>


<span class="hljs-comment">// User interface of the authenticated user</span>
<span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">string</span>;
}


<span class="hljs-keyword">class</span> MaxFileSize <span class="hljs-keyword">extends</span> FileValidator&lt;{ maxSize: <span class="hljs-built_in">number</span> }&gt;{
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">options: { maxSize: <span class="hljs-built_in">number</span> }</span>) {
    <span class="hljs-built_in">super</span>(options)
  }

  isValid(file: Express.Multer.File): <span class="hljs-built_in">boolean</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt; {
    <span class="hljs-keyword">const</span> in_mb = file.size / <span class="hljs-number">1000000</span>
    <span class="hljs-keyword">return</span> in_mb &lt;= <span class="hljs-built_in">this</span>.validationOptions.maxSize
  }
  buildErrorMessage(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`File uploaded is too big. Max size is (<span class="hljs-subst">${<span class="hljs-built_in">this</span>.validationOptions.maxSize}</span> MB)`</span>
  }
}

<span class="hljs-comment">/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */</span>
<span class="hljs-keyword">const</span> defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: <span class="hljs-function">(<span class="hljs-params">req: Request &amp; { user: User }, file, cb</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> uid = req.user.id;
    cb(<span class="hljs-literal">null</span>, <span class="hljs-string">`<span class="hljs-subst">${uid}</span><span class="hljs-subst">${path.extname(file.originalname)}</span>`</span>)
  }
})

<span class="hljs-meta">@ApiTags</span>(<span class="hljs-string">'Uploding Files'</span>)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-meta">@ApiConsumes</span>(<span class="hljs-string">'multipart/form-data'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
  <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
  uploadFile(
    <span class="hljs-meta">@UploadedFile</span>(
      <span class="hljs-keyword">new</span> ParseFilePipe({
        validators: [
          <span class="hljs-comment">// ... Set of file validator instances here</span>
          <span class="hljs-keyword">new</span> MaxFileSize({
            maxSize: MAX_UPLOAD_SIZE
          }),
        ]
      })
    )
    file: Express.Multer.File
  ) {
    <span class="hljs-built_in">console</span>.log(file);
  }

}
</code></pre>
<blockquote>
<p>If your validators are getting much, you can create them in a separate file and import them here as a named constant like <code>myValidators.</code> - <a target="_blank" href="https://docs.nestjs.com/techniques/file-upload#:~:text=.File%2C-,HINT,-If%20the%20number">NestJs Docs</a></p>
</blockquote>
<h3 id="heading-using-parsefilepipebuilder">Using ParseFilePipeBuilder</h3>
<p>Wow, this is amazing! It's so much better because it comes with built-in validators for file size and type! Plus, there's a way to add even more validators using the addValidator method for complex file validation! How cool is that?!</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ..., ParseFilePipeBuilder, HttpStatus } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
...

<span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
<span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
uploadFile(
  <span class="hljs-meta">@UploadedFile</span>(
    <span class="hljs-keyword">new</span> ParseFilePipeBuilder()
      .addFileTypeValidator({
        fileType: <span class="hljs-regexp">/(jpg|jpeg|png|gif)$/</span>,
      })
      .addMaxSizeValidator({
        maxSize: <span class="hljs-number">1000</span>
      })
      .addValidator(
        <span class="hljs-keyword">new</span> MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ) 
      .build({
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
      })
  )
  file: Express.Multer.File
) {
  <span class="hljs-built_in">console</span>.log(file);
}

...
</code></pre>
<p><code>errorHttpStatusCode</code> is the HTTP status code you want to be returned when validation fails.</p>
<p>Simplify the process of file validation with the help of ParseFilePipeBuilder. For straightforward validations like file types and sizes, this tool is highly recommended. However, for more intricate validations, it's best to create file validator classes.</p>
<h2 id="heading-optional-file-uploads">Optional File Uploads</h2>
<p>File upload parameters can be made optional or not required by passing an extra option in the <code>ParseFilePipeBuilder</code> build method.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">new</span> ParseFilePipeBuilder()
.addFileTypeValidator({
  fileType: <span class="hljs-string">"png"</span>,
})
.build({
  fileIsRequired: <span class="hljs-literal">false</span>  <span class="hljs-comment">// It's required by default</span>
})
</code></pre>
<h2 id="heading-accepting-multiple-files">Accepting multiple files</h2>
<p>Simply change the file interceptor and upload the file decorator.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { UploadedFiles } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FilesInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;

<span class="hljs-keyword">const</span> MAX_FILES_COUNT = <span class="hljs-number">10</span>;

...

<span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload/multiple'</span>)
<span class="hljs-meta">@UseInterceptors</span>(
  FilesInterceptor(<span class="hljs-string">'files'</span>, MAX_FILES_COUNT, { storage: defaultConfig })
)
uploadFiles(
  <span class="hljs-meta">@UploadedFiles</span>(
    <span class="hljs-keyword">new</span> ParseFilePipeBuilder()
      .addFileTypeValidator({
        fileType: <span class="hljs-regexp">/(jpg|jpeg|png|gif)$/</span>,
      })
      .addMaxSizeValidator({
        maxSize: <span class="hljs-number">1000</span>
      })
      .addValidator(
        <span class="hljs-keyword">new</span> MaxFileSize({
          maxSize: MAX_UPLOAD_SIZE
        }),
      ) 
      .build({
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
      })
  )
  files: Express.Multer.File[]
) {
  <span class="hljs-built_in">console</span>.log(files);
}

...
</code></pre>
<p>It's now <code>UploadedFiles</code> and <code>FilesInterceptor</code>. <code>FilesInterceptor</code> accepts max files number that can be uploaded through the endpoint.</p>
<blockquote>
<p>Make sure to accept files as an argument, not just file.</p>
</blockquote>
<p>Below, you can find the complete code.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Post, UploadedFile, UseInterceptors, Controller, ParseFilePipe, ParseFilePipeBuilder, HttpStatus, UploadedFiles } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor, FilesInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { ApiConsumes, ApiTags } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;
<span class="hljs-keyword">import</span> { Request } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;
<span class="hljs-keyword">import</span> { diskStorage } <span class="hljs-keyword">from</span> <span class="hljs-string">'multer'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'path'</span>;
<span class="hljs-keyword">import</span> { FileValidator } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-keyword">const</span> UPLOAD_DIR = <span class="hljs-string">'./upload/files/'</span>;
<span class="hljs-keyword">const</span> MAX_UPLOAD_SIZE = <span class="hljs-number">10</span>; <span class="hljs-comment">// in MB</span>
<span class="hljs-keyword">const</span> MAX_FILES_COUNT = <span class="hljs-number">10</span>; <span class="hljs-comment">// Maximum number of files that can be uploaded at once</span>


<span class="hljs-comment">// User interface of the authenticated user</span>
<span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">string</span>;
}


<span class="hljs-keyword">class</span> MaxFileSize <span class="hljs-keyword">extends</span> FileValidator&lt;{ maxSize: <span class="hljs-built_in">number</span> }&gt;{
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">options: { maxSize: <span class="hljs-built_in">number</span> }</span>) {
    <span class="hljs-built_in">super</span>(options)
  }

  isValid(file: Express.Multer.File): <span class="hljs-built_in">boolean</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt; {
    <span class="hljs-keyword">const</span> in_mb = file.size / <span class="hljs-number">1000000</span>
    <span class="hljs-keyword">return</span> in_mb &lt;= <span class="hljs-built_in">this</span>.validationOptions.maxSize
  }
  buildErrorMessage(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`File uploaded is too big. Max size is (<span class="hljs-subst">${<span class="hljs-built_in">this</span>.validationOptions.maxSize}</span> MB)`</span>
  }
}

<span class="hljs-comment">/**
 * You can use this function to generate a unique filename for each file
 * User id is used to generate a unique filename
 * The User object can be attached to the request object in the auth middleware
 */</span>
<span class="hljs-keyword">const</span> defaultConfig = diskStorage({
  destination: UPLOAD_DIR,
  filename: <span class="hljs-function">(<span class="hljs-params">req: Request &amp; { user: User }, file, cb</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> uid = req.user.id;
    cb(<span class="hljs-literal">null</span>, <span class="hljs-string">`<span class="hljs-subst">${uid}</span><span class="hljs-subst">${path.extname(file.originalname)}</span>`</span>)
  }
})

<span class="hljs-meta">@ApiTags</span>(<span class="hljs-string">'Uploding Files'</span>)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'files'</span>)
<span class="hljs-meta">@ApiConsumes</span>(<span class="hljs-string">'multipart/form-data'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileController {

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload'</span>)
  <span class="hljs-meta">@UseInterceptors</span>(FileInterceptor(<span class="hljs-string">'file'</span>, { storage: defaultConfig }))
  uploadFile(
    <span class="hljs-meta">@UploadedFile</span>(
      <span class="hljs-keyword">new</span> ParseFilePipeBuilder()
        .addFileTypeValidator({
          fileType: <span class="hljs-regexp">/(jpg|jpeg|png|gif)$/</span>,
        })
        .addMaxSizeValidator({
          maxSize: <span class="hljs-number">1000</span>
        })
        .build({
          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
        })
    )
    file: Express.Multer.File
  ) {
    <span class="hljs-built_in">console</span>.log(file);
  }

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'upload/multiple'</span>)
  <span class="hljs-meta">@UseInterceptors</span>(
    FilesInterceptor(<span class="hljs-string">'files'</span>, MAX_FILES_COUNT, { storage: defaultConfig })
  )
  uploadFiles(
    <span class="hljs-meta">@UploadedFiles</span>(
      <span class="hljs-keyword">new</span> ParseFilePipeBuilder()
        .addFileTypeValidator({
          fileType: <span class="hljs-regexp">/(jpg|jpeg|png|gif)$/</span>,
        })
        .addValidator(
          <span class="hljs-keyword">new</span> MaxFileSize({
            maxSize: MAX_UPLOAD_SIZE
          }),
        )
        .build({
          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY
        })
    )
    files: Express.Multer.File[]
  ) {
    <span class="hljs-built_in">console</span>.log(files);
  }
}
</code></pre>
<p>For a comprehensive configuration of Multer file upload, refer to the NestJs File Upload <a target="_blank" href="https://docs.nestjs.com/techniques/file-upload">Documentation</a>. Read on to learn more.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, this article provides a comprehensive guide on how to implement file upload and validation in NestJS using the Multer middleware package for the Express Adapter. It covers accepting and validating files, saving files to disk storage, file validation with ParseFilePipe and ParseFilePipeBuilder, and accepting multiple files. By following the steps outlined in this article, developers can easily design their custom file upload and validation flow in NestJS.</p>
]]></content:encoded></item><item><title><![CDATA[Building an ECDSA wallet with JavaScript]]></title><description><![CDATA[Blockchain is an amazing technology to dive into. It has been around for some time now and powering very popular technologies like Ethereum.
To make this article as simple as possible, the definitions and terminologies would be summarized to just key...]]></description><link>https://blog.covenlabs.space/building-an-ecdsa-wallet-with-javascript</link><guid isPermaLink="true">https://blog.covenlabs.space/building-an-ecdsa-wallet-with-javascript</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[React]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sun, 29 Jan 2023 19:05:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673707951056/456596b6-fc44-44de-940f-6260c8dc8c4a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Blockchain</strong> is an amazing technology to dive into. It has been around for some time now and powering very popular technologies like Ethereum.</p>
<p>To make this article as simple as possible, the definitions and terminologies would be summarized to just key points needed for the project you will build in this article. But links to amazing educational articles will be provided for each.</p>
<p>By the end of this article, you would understand Public Key Cryptography, Elliptic curve digital signatures and how they can be used to make the world a better place. I will take you one step at a time on how to build a blockchain node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673692523279/b7cd2eb1-153b-4ba6-afa3-2cdc9cdd6550.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-is-cryptography">What is Cryptography</h2>
<p>Cryptography is a way of securing a piece of information. It's the study of cryptographic hash functions.</p>
<p>Cryptographic hash functions are mathematical functions that take an input of any size and convert it to a fixed-sized output. It's a one-way ticket, you can't get the input from the output.</p>
<p>Cryptography is at the heart of blockchain and Web3. Here is an <a target="_blank" href="https://emn178.github.io/online-tools/sha256">online tool</a> containing lots of hash functions you can play with.</p>
<h3 id="heading-public-key-cryptography">Public Key Cryptography</h3>
<p>It's the use of two keys, a public key (a key that is known to everyone), and a private key (a key that is kept secured). The private key can encrypt a message that can only be decrypted by the public key, verifying that the message was indeed sent by someone with the right private key and vice versa.</p>
<p>Public key cryptography is also called <strong>asymmetric cryptography</strong> because it uses a pair of related keys.</p>
<p>RSA and ECDSA are two popular algorithms used for public cryptography. RSA is based on the idea that you can quickly find the product of two prime numbers, but extremely hard to factor out the prime numbers once you have the products. Read more about <a target="_blank" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Example">RSA</a>.</p>
<p>ECDSA (Elliptic curve digital signature algorithm) uses elliptic curves. Read more about it on <a target="_blank" href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">Wikipedia</a>.</p>
<h3 id="heading-why-use-ecdsa">Why use ECDSA</h3>
<p>ECDSA provides the same level of security as RSA but with small key sizes. RSA keys can be very large making it take a long to transfer over a network.</p>
<p>ECDSA is the algorithm used by Bitcoin, which is the <a target="_blank" href="https://en.bitcoin.it/wiki/Secp256k1">secp256k1 curve</a>.</p>
<h2 id="heading-building-an-ecdsa-node">Building an ECDSA node</h2>
<p>This is an example of a blockchain node that uses the ECDSA signing algorithm. The project is a simple react frontend application that allows users to send money to each other. There will be a single server node, which makes this centralized but there will be an article later on how to deploy a program on Ethereum.</p>
<h2 id="heading-goal">Goal</h2>
<p>The server would manage the balances of the users. The goal is to enable the server to verify who is sending the money to make sure that a person can only send money from their wallet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673692754409/53f620dd-f12d-4a28-bb9e-af5e6b454417.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-project-prerequisites">Project prerequisites</h3>
<p>You will need to have a basic knowledge of React as it is used for the front end. With a basic understanding of Express.</p>
<h3 id="heading-application-architecture">Application Architecture</h3>
<p>There is the front end, which has the UI part of the project that allows users to enter their wallet addresses and attempt to send money to others. The Idea here is that, when a user tries to send money, we would generate a transaction for them to sign with their private key, then input the signed transaction which would be sent to the server with their public key (wallet address), address where money should be sent, and the amount of money to be sent.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673692925118/075ad9c4-4c2d-4480-9a17-bd607194e52d.png" alt class="image--center mx-auto" /></p>
<p>The server would take this signed transaction and the public key, then verify if the transaction was indeed signed using the right private key of the public key. If it's correct, it updates the users (sender and recipient) balances, else it returns an error message.</p>
<h3 id="heading-client-side-react-app">Client-Side React App</h3>
<p>We would use Vite for our front-end tooling.</p>
<p>Create a new directory called <code>wallet-node</code> and move into the directory.</p>
<p>Run <code>npm create vite@latest</code>, enter <code>client</code> as your project name, <code>react</code> as the framework and <code>JavaScript</code> as the variant.</p>
<p>Move into the client directory just created by Vite. Run <code>npm i</code> to install the packages from the template.</p>
<p>Install Sass as a dev dependency using this command <code>npm i -D sass</code>. This will install the sass package as we will be using sass for our CSS styling.</p>
<p>The last installments are:</p>
<ol>
<li><p>Axios - <code>npm i axios</code></p>
</li>
<li><p>Ethereum Cryptography - <code>npm i ethereum-cryptography</code></p>
</li>
</ol>
<p>Now, edit the value of the title tag in the index.html file to <code>ECDSA Wallet</code> or anything you want.</p>
<p>Move into the <code>src</code> directory, delete the <code>assets</code> directory, <code>index.css</code> and <code>App.css</code> files.</p>
<p>Edit the <code>main.jsx</code> file, remove the line for <code>import './index.css'</code>.</p>
<p>Edit <code>App.jsx</code> by removing everything in it and pasting in the following code;</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Wallet <span class="hljs-keyword">from</span> <span class="hljs-string">"./Wallet"</span>;
<span class="hljs-keyword">import</span> Transfer <span class="hljs-keyword">from</span> <span class="hljs-string">"./Transfer"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.scss"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [balance, setBalance] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [address, setAddress] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"app"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Wallet</span>
        <span class="hljs-attr">balance</span>=<span class="hljs-string">{balance}</span>
        <span class="hljs-attr">setBalance</span>=<span class="hljs-string">{setBalance}</span>
        <span class="hljs-attr">address</span>=<span class="hljs-string">{address}</span>
        <span class="hljs-attr">setAddress</span>=<span class="hljs-string">{setAddress}</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Transfer</span> <span class="hljs-attr">setBalance</span>=<span class="hljs-string">{setBalance}</span> <span class="hljs-attr">address</span>=<span class="hljs-string">{address}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>We will create a Wallet and Transfer component, and our <code>App.scss</code> file for the sass styles.</p>
<p>From the above code, two stateful values were created, <code>balance</code> and <code>address</code>. The <code>balance</code> will be used to keep track of and manage an address balance, while the <code>address</code> will be used to share a user address among the <code>Wallet</code> and <code>Transfer</code> components.</p>
<p>The transfer component accepts a prop <code>setBalance</code> which would be used to set the state of the user's balance after the money has been transferred successfully.</p>
<p>Create an <code>App.scss</code> file in the <code>src</code> directory, then paste the following code;</p>
<pre><code class="lang-scss"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Muli"</span>, sans-serif;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">300</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#e2e8f0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">40px</span>;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.05rem</span>;
  <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">8em</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#222</span>;
}

<span class="hljs-selector-class">.app</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1400px</span>;
  <span class="hljs-attribute">flex-wrap</span>: wrap;
  gap: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#cbd5e0</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">1px</span> <span class="hljs-number">2px</span> <span class="hljs-number">0</span> rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.05</span>);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.375rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">40px</span>;

  <span class="hljs-selector-tag">label</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">10px</span> <span class="hljs-number">0</span>;
  }

  <span class="hljs-selector-class">.button</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
  }
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.125rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid rgb(<span class="hljs-number">226</span>, <span class="hljs-number">232</span>, <span class="hljs-number">240</span>);
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fdfdfe</span>;
  <span class="hljs-attribute">padding</span>-inline-start: <span class="hljs-number">0.75rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.875rem</span>;
}

<span class="hljs-selector-class">.button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#319795</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.125rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">display</span>: inline-flex;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">1px</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
  <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">9em</span>;
  &amp;<span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">cursor</span>: pointer;
  }
}

<span class="hljs-selector-class">.wallet</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;

  <span class="hljs-selector-class">.balance</span> {
    <span class="hljs-attribute">text-transform</span>: uppercase;
    <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
    <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">9em</span>;
    <span class="hljs-attribute">display</span>: inline-flex;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f4f6f8</span>;
  }
}

<span class="hljs-selector-class">.transfer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
}
</code></pre>
<p>Create a <code>server.js</code> file and paste the code below;</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> server = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"http://localhost:3042"</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> server;
</code></pre>
<p>This creates an Axios instance that uses <code>http://localhost:3042</code> as the base URL, this is the URL our server will be listening on. The Axios instance is exported to be used by other services.</p>
<p>Now we would need to create a very important function. Here we would use cryptographic functions 😁. Specifically, the <code>keccak256</code> hash function, which would be used to hash our transaction messages.</p>
<p>Create a `services.js` file, and paste the code below;</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { keccak256 } <span class="hljs-keyword">from</span> <span class="hljs-string">"ethereum-cryptography/keccak"</span>
<span class="hljs-keyword">import</span> { utf8ToBytes, toHex } <span class="hljs-keyword">from</span> <span class="hljs-string">"ethereum-cryptography/utils"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hashMessage</span>(<span class="hljs-params">message</span>)</span>{
    <span class="hljs-keyword">return</span> toHex(keccak256(utf8ToBytes(message)))
}
</code></pre>
<p>Now let's talk about what is happening here.</p>
<p>We have created a <code>hashMessage</code> function, which accepts a message (string) and returns a hash (string).</p>
<p>Keccak256, the function is imported from the Ethereum cryptography package installed earlier, it accepts bytes (Uint8Array) and returns a hash of fixed-sized output. The return type of this hash is a byte. The <code>utf8ToBytes</code> converts the message passed to the function to bytes which are then passed to the <code>keccak256</code> function.</p>
<p>Finally, the function, <code>toHex</code>, takes the returned bytes from the <code>keccak256</code> function and converts it to a hexadecimal string, which is then returned by the <code>hashMessage</code> function.</p>
<p>Its purpose is to encrypt a transaction message which would then be sent to the user to sign with their private key 🔑.</p>
<p><strong>Creating the Wallet Component</strong></p>
<p>The functionality of this component is to allow the user to input any address and see its balance. Create a <code>Wallet.jsx</code> file in the <code>src</code> directory, then copy and paste the code below into the file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> server <span class="hljs-keyword">from</span> <span class="hljs-string">"./server"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Wallet</span>(<span class="hljs-params">{ address, setAddress, balance, setBalance }</span>) </span>{
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onChange</span>(<span class="hljs-params">evt</span>) </span>{
    <span class="hljs-keyword">const</span> address = evt.target.value;
    setAddress(address);
    <span class="hljs-keyword">if</span> (address) {
      <span class="hljs-keyword">const</span> {
        <span class="hljs-attr">data</span>: { balance },
      } = <span class="hljs-keyword">await</span> server.get(<span class="hljs-string">`balance/<span class="hljs-subst">${address}</span>`</span>);
      setBalance(balance);
    } <span class="hljs-keyword">else</span> {
      setBalance(<span class="hljs-number">0</span>);
    }
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container wallet"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Your Wallet<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Wallet Address
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type an address, for example: 0x1"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{address}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{onChange}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"balance"</span>&gt;</span>Balance: {balance}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Wallet;
</code></pre>
<p>Every time the input changes it will invoke the <code>onChange</code> event handler which will request the address balance from the server. If successful it will update the balance state using the <code>setBalance</code> action. The Balance and Address states are created from the <code>App.jsx</code> App component because their states will be used by the Transfer component too.</p>
<p><strong>Transfer Component</strong></p>
<p>This component will be used by the user to send any amount to any recipient. Create a <code>Transfer.jsx</code> file in the <code>src</code> directory, then copy and paste the code below into the file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> server <span class="hljs-keyword">from</span> <span class="hljs-string">"./server"</span>;
<span class="hljs-keyword">import</span> { hashMessage } <span class="hljs-keyword">from</span> <span class="hljs-string">"./services"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Transfer</span>(<span class="hljs-params">{ address, setBalance }</span>) </span>{
  <span class="hljs-keyword">const</span> [sendAmount, setSendAmount] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [recipient, setRecipient] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> setValue = <span class="hljs-function">(<span class="hljs-params">setter</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">evt</span>) =&gt;</span> setter(evt.target.value);

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

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">let</span> data = {
        recipient,
        <span class="hljs-attr">amount</span>: <span class="hljs-built_in">parseInt</span>(sendAmount)
      }
      <span class="hljs-keyword">let</span> msgHex = <span class="hljs-keyword">await</span> hashMessage(<span class="hljs-built_in">JSON</span>.stringify(data))
      <span class="hljs-keyword">let</span> signature = prompt(<span class="hljs-string">`Sign message (<span class="hljs-subst">${msgHex}</span>) and provide signature:`</span>)
      <span class="hljs-keyword">if</span> (signature === <span class="hljs-literal">null</span>){
        alert(<span class="hljs-string">"You did not provided a signature"</span>)
        <span class="hljs-keyword">return</span>
      }
      <span class="hljs-keyword">await</span> transfer(signature)
    } <span class="hljs-keyword">catch</span> (ex) {
      alert(ex.response.data.message);
    }

  }

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params">signature</span>) </span>{
    <span class="hljs-keyword">const</span> {
      <span class="hljs-attr">data</span>: { balance },
    } = <span class="hljs-keyword">await</span> server.post(<span class="hljs-string">`send`</span>, {
      <span class="hljs-attr">sender</span>: address,
      <span class="hljs-attr">amount</span>: <span class="hljs-built_in">parseInt</span>(sendAmount),
      recipient,
      signature,
    });
    setBalance(balance);
    alert(<span class="hljs-string">"Funds transferred successfully!"</span>)
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container transfer"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{getSignature}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Send Transaction<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Send Amount
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"1, 2, 3..."</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{sendAmount}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{setValue(setSendAmount)}</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Recipient
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type an address, for example: 0x2"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{recipient}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{setValue(setRecipient)}</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Transfer"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Transfer;
</code></pre>
<p>This is a lot, so let's break it down.</p>
<pre><code class="lang-javascript">...
function Transfer({ address, setBalance })
...
</code></pre>
<p>The transfer component accepts two values;</p>
<ul>
<li><p>address - state object which is the sender's (user's) address</p>
</li>
<li><p>setBalance - state action which will be used to update the user's balance</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [sendAmount, setSendAmount] = useState(<span class="hljs-string">""</span>);
<span class="hljs-keyword">const</span> [recipient, setRecipient] = useState(<span class="hljs-string">""</span>);
</code></pre>
<p>These states are used to set the amount to be sent and the recipient's address.</p>
<pre><code class="lang-javascript">...
const setValue = <span class="hljs-function">(<span class="hljs-params">setter</span>) =&gt;</span> <span class="hljs-function">(<span class="hljs-params">evt</span>) =&gt;</span> setter(evt.target.value);
...
</code></pre>
<p>This function takes in a callable, <code>setter</code> as an argument and returns an event handler. The function of the event handler is to pass the target value of the event object as an argument to <code>setter</code>.</p>
<p>It's used here;</p>
<pre><code class="lang-javascript">...
&lt;label&gt;
  Send Amount
  &lt;input
    placeholder=<span class="hljs-string">"1, 2, 3..."</span>
    value={sendAmount}
    onChange={setValue(setSendAmount)}
  &gt;&lt;/input&gt;
&lt;/label&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
  Recipient
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type an address, for example: 0x2"</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{recipient}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{setValue(setRecipient)}</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
...
</code></pre>
<p>The function, <code>setValue</code> , is used for the onChange events of both inputs above. Which updates the states of both amount and recipient with the values of their respective inputs.</p>
<p>Now, the function, <code>getSignature</code> , will be demystified. The goal here is that when the user enters a recipient address, the amount to be sent, and submits the form. A transaction object will be created which will contain the amount and recipient address, this transaction will then be displayed to the user so that they can sign it with their private key 🔑. Then the signature will be passed to the transfer function.</p>
<pre><code class="lang-javascript">...
async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSignature</span>(<span class="hljs-params">evt</span>)</span>{
  evt.preventDefault();

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">let</span> data = {
      recipient,
      <span class="hljs-attr">amount</span>: <span class="hljs-built_in">parseInt</span>(sendAmount)
    }
    <span class="hljs-keyword">let</span> msgHex = <span class="hljs-keyword">await</span> hashMessage(<span class="hljs-built_in">JSON</span>.stringify(data))
    <span class="hljs-keyword">let</span> signature = prompt(<span class="hljs-string">`Sign message (<span class="hljs-subst">${msgHex}</span>) and provide signature:`</span>)
    <span class="hljs-keyword">if</span> (signature === <span class="hljs-literal">null</span>){
      alert(<span class="hljs-string">"You did not provided a signature"</span>)
      <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">await</span> transfer(signature)
  } <span class="hljs-keyword">catch</span> (ex) {
    alert(ex.response.data.message);
  }
}
...
</code></pre>
<p>The <code>transfer</code> function;</p>
<pre><code class="lang-javascript">...
async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params">signature</span>) </span>{
  <span class="hljs-keyword">const</span> {
    <span class="hljs-attr">data</span>: { balance },
  } = <span class="hljs-keyword">await</span> server.post(<span class="hljs-string">`send`</span>, {
    <span class="hljs-attr">sender</span>: address,
    <span class="hljs-attr">amount</span>: <span class="hljs-built_in">parseInt</span>(sendAmount),
    recipient,
    signature,
  });
  setBalance(balance);
  alert(<span class="hljs-string">"Funds transferred successfully!"</span>)
}
...
</code></pre>
<p>This sends the signature and the transaction data to the server. If the signature is valid for the transaction data, then the money will be transferred to the recipient's address.</p>
<p>That's all for the client-side application.</p>
<h3 id="heading-server-side-nodejs-application">Server-Side NodeJS Application</h3>
<p>The backend will be an express application. It's going to have two simple handlers;</p>
<ul>
<li><p>GET /balance/:address - to get an address balance</p>
</li>
<li><p>POST /send - to transfer funds from one address to another.</p>
</li>
</ul>
<p>Also, we would need to create some useful scripts for generating new random wallets and signing transactions. The latter is meant to help users sign transaction messages with their private key 🔑.</p>
<p>Firstly, let's set up the server directory. If not already created, create a new directory, <code>server</code> , in the root directory. Move into the directory, and run <code>npm init -y</code> to initialize the default <code>package.json</code> file.</p>
<p>Copy and paste the content below into the <code>package.json</code> file.</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"server"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"generate"</span>: <span class="hljs-string">"node ./scripts/gen.js"</span>,
    <span class="hljs-string">"sign"</span>: <span class="hljs-string">"node ./scripts/signer.js"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  },
  <span class="hljs-string">"keywords"</span>: [],
  <span class="hljs-string">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-string">"license"</span>: <span class="hljs-string">"ISC"</span>,
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"cors"</span>: <span class="hljs-string">"^2.8.5"</span>,
    <span class="hljs-string">"ethereum-cryptography"</span>: <span class="hljs-string">"^1.1.2"</span>,
    <span class="hljs-string">"express"</span>: <span class="hljs-string">"^4.18.1"</span>,
    <span class="hljs-string">"yargs"</span>: <span class="hljs-string">"^17.6.2"</span>
  }
}
</code></pre>
<p>Then run <code>npm install</code> to install dependencies.</p>
<p>Before creating the scripts for <code>generate</code> and <code>sign</code>, we will be creating <code>services.js</code> first to define shared functions.</p>
<p><strong>Services</strong></p>
<p>Create a new file <code>service.js</code> in the <code>server</code> directory. Copy and paste the code below into it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> secp = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ethereum-cryptography/secp256k1"</span>);
<span class="hljs-keyword">const</span> { keccak256 } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ethereum-cryptography/keccak"</span>)
<span class="hljs-keyword">const</span> { utf8ToBytes, toHex } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ethereum-cryptography/utils"</span>)


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">extractPublicKey</span>(<span class="hljs-params">fullKey</span>)</span>{
    <span class="hljs-keyword">let</span> kec = keccak256(fullKey.slice(<span class="hljs-number">1</span>, fullKey.length));
    <span class="hljs-keyword">return</span> toHex(kec.slice(kec.length - <span class="hljs-number">20</span>, kec.length))
}


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">verifySignature</span>(<span class="hljs-params">sig, msg, pubKey</span>)</span>{
    <span class="hljs-keyword">const</span> msgHash = keccak256(utf8ToBytes(msg));
    <span class="hljs-keyword">let</span> actualSignature = sig.slice(<span class="hljs-number">0</span>, sig.length - <span class="hljs-number">1</span>)
    <span class="hljs-keyword">let</span> recoveryBit = <span class="hljs-built_in">parseInt</span>(sig[sig.length - <span class="hljs-number">1</span>])
    <span class="hljs-keyword">const</span> sigPubKey = secp.recoverPublicKey(msgHash, actualSignature, recoveryBit);
    <span class="hljs-keyword">const</span> mainKey = extractPublicKey(sigPubKey);
    <span class="hljs-keyword">return</span> mainKey == pubKey
}

<span class="hljs-built_in">module</span>.exports = {
    verifySignature,
    extractPublicKey
}
</code></pre>
<p>The function, <code>extractPublicKey</code>, accepts bytes array as an argument, this is the byte format of a full public key. Then hashes it with <code>keccak256</code> and returns the hexadecimal string of the last 20 bytes of the hash. <a target="_blank" href="https://ethereum.org/en/developers/docs/accounts/#key-differences:~:text=The%20public%20key%20is%20generated%20from%20the%20private%20key%20using%20the%20Elliptic%20Curve%20Digital%20Signature%20Algorithm.%20You%20get%20a%20public%20address%20for%20your%20account%20by%20taking%20the%20last%2020%20bytes%20of%20the%20Keccak%2D256%20hash%20of%20the%20public%20key%20and%20adding%200x%20to%20the%20beginning">Ethereum docs</a> explains why it's required. It's to make it shorter 😉.</p>
<p>The last function, <code>verifySignature</code>, accepts a signature, a transaction message, and the sender's public key. All this data is required to verify that the transaction message was indeed signed using the private key of the owner of the public key.</p>
<p>The function hashes the transaction message and used [recoverPublicKey](https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=%3A%20boolean%0Afunction-,recoverPublicKey,-(msgHash%3A) to get the public key of the signer. After extracting the short format using <code>extractPublicKey</code>, it compares it will the public key, <code>pubKey</code>, passed to the function.</p>
<p><strong>Script - generate:</strong> Generating new random public and private key pairs</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> secp = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ethereum-cryptography/secp256k1"</span>)
<span class="hljs-keyword">const</span> { toHex } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ethereum-cryptography/utils'</span>)
<span class="hljs-keyword">const</span> { extractPublicKey } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../services'</span>)


<span class="hljs-keyword">let</span> privateKey = secp.utils.randomPrivateKey();
<span class="hljs-keyword">let</span> pubKey = secp.getPublicKey(privateKey)

pubKey = extractPublicKey(pubKey)

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Private key:"</span>, toHex(privateKey))
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Public key:"</span>, pubKey)
</code></pre>
<p>A new private key is generated using the <a target="_blank" href="https://github.com/ethereum/js-ethereum-cryptography#secp256k1-curve:~:text=We%20strongly%20recommend%20using%20utils.randomPrivateKey()%20to%20generate%20them">randomPrivatekey</a> function. The public key is also extracted from the private key. The mathematical property that made this possible is so amazing. The private key can never be known from the public key.</p>
<p><strong>Script usage example:</strong></p>
<pre><code class="lang-bash">npm run generate
</code></pre>
<p><strong>Console output:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675013519885/59fef63a-1cd9-430d-9a96-19d199ffc174.png" alt class="image--center mx-auto" /></p>
<p><strong>Script - sign:</strong> Signing transaction messages</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> yargs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'yargs/yargs'</span>)
<span class="hljs-keyword">const</span> { hideBin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'yargs/helpers'</span>)
<span class="hljs-keyword">const</span> secp = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ethereum-cryptography/secp256k1'</span>)
<span class="hljs-keyword">const</span> { toHex } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"ethereum-cryptography/utils"</span>)


<span class="hljs-keyword">let</span> args = yargs(hideBin(process.argv))
    .option(<span class="hljs-string">'private_key'</span>, {
        <span class="hljs-attr">alias</span>: <span class="hljs-string">'p'</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">'string'</span>,
        <span class="hljs-attr">description</span>: <span class="hljs-string">'Your Private Key'</span>,
        <span class="hljs-attr">demandOption</span>: <span class="hljs-literal">true</span>
    })
    .option(<span class="hljs-string">'data'</span>, {
        <span class="hljs-attr">alias</span>: <span class="hljs-string">'d'</span>,
        <span class="hljs-attr">type</span>: <span class="hljs-string">'string'</span>,
        <span class="hljs-attr">description</span>: <span class="hljs-string">'Payload to sign'</span>,
        <span class="hljs-attr">demandOption</span>: <span class="hljs-literal">true</span>
    })
    .parse()


<span class="hljs-keyword">let</span> privKey = args.private_key
<span class="hljs-keyword">let</span> msgHash = args.data

secp.sign(secp.utils.hexToBytes(msgHash), privKey, { <span class="hljs-attr">recovered</span>: <span class="hljs-literal">true</span> }).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> [signature, recovery_bit] = data
    <span class="hljs-keyword">let</span> sig = toHex(signature);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Your Signature:"</span>, sig)
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Your Recovery Bit:"</span>, recovery_bit)
    <span class="hljs-keyword">let</span> fullSig = sig + recovery_bit.toString()
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Copy and paste this as the full signature, this has the recovery bit attached to the end:\n"</span>, fullSig)
})
</code></pre>
<p>This is more of a CLI tool. It accepts the private key and message hash as command-line arguments. The <code>sign</code> function from the module, <code>ethereum-cryptography/secp256k1</code> , is used to sign the message hash, <code>msgHash</code>. The result of the <code>signature</code> and <code>recovery_bit</code> received from the data are later concatenated to form a single string, signature, which is logged to the console.</p>
<p>The signature is expected in the component, <code>Transfer</code> , in the client-side application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675013270992/2a3a1e68-b5d8-4502-8d1b-0c8e1349d298.png" alt class="image--center mx-auto" /></p>
<p>So the user can copy it from the console and paste it into the prompt.</p>
<p><strong>Script usage example</strong></p>
<pre><code class="lang-bash">npm run sign -- -p 3ebefedbd43cbd88f0504acd101df139ddce0656da699b8350c1db9eaf193484 -d 3ebefedbd43cbd88f0504acd101df139ddce0656da699b8350c1db9eaf178970
</code></pre>
<p><strong>Console output:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675013783072/5c88991a-1e10-4399-be3f-b5a85e5cb8a9.png" alt class="image--center mx-auto" /></p>
<p>Now create the <code>index.js</code> file, which will contain our API routes and handlers, in the <code>src</code> directory.</p>
<p>Follow the steps below and paste the codes gradually.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3042</span>;
<span class="hljs-keyword">const</span> { verifySignature } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./services"</span>)


app.use(cors());
app.use(express.json());

<span class="hljs-keyword">const</span> balances = {
  <span class="hljs-string">"KEY_A"</span>: <span class="hljs-number">100</span>,
  <span class="hljs-string">"KEY_B"</span>: <span class="hljs-number">50</span>,
  <span class="hljs-string">"KEY_C"</span>: <span class="hljs-number">75</span>,
  <span class="hljs-comment">// KEY_N: Any amount</span>
};
</code></pre>
<p>The object, <code>balances</code> , is currently acting as the database. The keys of the object will be public keys of different wallets, and the values will be their respective balance.</p>
<p>New public and private key pairs can be generated using the <code>generate</code> script. After creating any amount of key pairs, update the object, <code>balances</code>, with the public keys. Make sure to save their respective private keys too, so they can be used later for signing transaction messages.</p>
<p><strong>GET - /balance/:address</strong></p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">"/balance/:address"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { address } = req.params;
  <span class="hljs-keyword">const</span> balance = balances[address] || <span class="hljs-number">0</span>;
  res.send({ balance });
});
</code></pre>
<p>This is the route used to get an address balance.</p>
<p><strong>POST - /send</strong></p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">"/send"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { sender, recipient, amount, signature } = req.body;

  <span class="hljs-keyword">const</span> msg = <span class="hljs-built_in">JSON</span>.stringify({
    recipient,
    amount
  })
  <span class="hljs-keyword">let</span> isValid = verifySignature(signature, msg, sender);
  <span class="hljs-keyword">if</span> (isValid === <span class="hljs-literal">false</span>){
    res.status(<span class="hljs-number">400</span>).send({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Invalid Signature!"</span> })
    <span class="hljs-keyword">return</span>
  }

  setInitialBalance(sender);
  setInitialBalance(recipient);

  <span class="hljs-keyword">if</span> (balances[sender] &lt; amount) {
    res.status(<span class="hljs-number">400</span>).send({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Not enough funds!"</span> });
  } <span class="hljs-keyword">else</span> {
    balances[sender] -= amount;
    balances[recipient] += amount;
    res.send({ <span class="hljs-attr">balance</span>: balances[sender] });
  }
});
</code></pre>
<p>This route verifies the amount and recipient, against the signature and public key of the sender. If the signature is valid, it tries to debit the sender, if this is successful it will update the recipient balance.</p>
<p>Lastly,</p>
<pre><code class="lang-javascript">app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Listening on port <span class="hljs-subst">${port}</span>!`</span>);
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setInitialBalance</span>(<span class="hljs-params">address</span>) </span>{
  <span class="hljs-keyword">if</span> (!balances[address]) {
    balances[address] = <span class="hljs-number">0</span>;
  }
}
</code></pre>
<p>Start the server to listen on any given port.</p>
<blockquote>
<p>If the port is changed, make sure it's also updated in the client application.</p>
</blockquote>
<p>The function, <code>setInitialBalance</code>, checks if an address exists in the database. If the address does not exist, it adds the address to the database with a balance of zero. This is a very nice method, as we don't need to manually add new users to our database.</p>
<p>Project codes are <a target="_blank" href="https://github.com/devvspaces/ecdsa-node">Github</a></p>
<h2 id="heading-resources">Resources</h2>
<p>Cryptographic tools for Ethereum - <a target="_blank" href="https://www.npmjs.com/package/ethereum-cryptography">Ethereum Cryptography</a></p>
<p>Node CLI tool - <a target="_blank" href="https://www.npmjs.com/package/yargs">Yargs</a></p>
<p>Play with Cryptographic hashes - <a target="_blank" href="https://emn178.github.io/online-tools/sha256">SHA256 Online tool</a></p>
<p>Public Key Cryptography - <a target="_blank" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA Algorithm</a> &amp; <a target="_blank" href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">Elliptic Digital Curves (ECDSA)</a></p>
<p>Cryptography in HTTPS - <a target="_blank" href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">Diffie Hellman Key Exchange</a> &amp; <a target="_blank" href="https://security.stackexchange.com/a/41226">TLS handshake for HTTPS</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The idea presented in this article can also be used in several fields of technology to maintain data integrity when data is transferred between several components through a network.</p>
<p>One flaw of the server built today is that it's a single node, which makes the database a centralized instance. This is where a blockchain ledger would be useful because it's managed by more nodes which are all bound by rules (consensus) making the whole system decentralized. An account with a public key, <code>TEST</code>, on <code>node A</code>, would have the same balance on <code>node B</code>.</p>
<p>Building applications on the blockchain will be covered later in new articles, subscribe to the newsletter to receive notifications when new articles drop.</p>
<p>Follow me on Twitter <a target="_blank" href="https://twitter.com/netrobeweb">netrobeweb</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Working with strings effectively with Golang]]></title><description><![CDATA[What are Strings? 🤔
The way strings is stored in memory makes them immutable, making it difficult to perform simple operations like changing the value of an index in a string. For example you can't perform an index assignment operation on a string, ...]]></description><link>https://blog.covenlabs.space/working-with-strings-effectively-with-golang</link><guid isPermaLink="true">https://blog.covenlabs.space/working-with-strings-effectively-with-golang</guid><category><![CDATA[string]]></category><category><![CDATA[beginner]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[#codingNewbies]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sun, 09 Oct 2022 01:26:46 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-what-are-strings">What are Strings? 🤔</h1>
<p>The way strings is stored in memory makes them immutable, making it difficult to perform simple operations like changing the value of an index in a string. For example you can't perform an index assignment operation on a string, but this is possible with arrays. Golang has a built-in library that can help us work with strings. We are able to read and manipulate strings in various ways.</p>
<p>In this tutorial series, we would discuss about ways we can manipulate a string in Golang. By looking into</p>
<ul>
<li>Peeking,</li>
<li>Traversing,</li>
<li>Mutating, and</li>
<li>Sorting</li>
</ul>
<p>of strings in Golang, you should be confident enough to work with them in any aspect of programming you come across.</p>
<h1 id="heading-working-with-strings">Working with Strings 🛩️</h1>
<h2 id="heading-peeking">Peeking</h2>
<p>In this use case Peeking means inspecting a string trying to find what it looks like. For example, checking the first character of a string, the character at an index, the characters in a range of two index, etc.</p>
<h3 id="heading-testing-the-first-and-last-characters-of-a-string">Testing the first and last characters of a string</h3>
<p>We can test what starts (prefixes) and ends (suffixes) a string.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strings"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> str <span class="hljs-keyword">string</span> = <span class="hljs-string">"Hashnode is a very easy tool to use for blogging"</span>
    fmt.Printf(<span class="hljs-string">"T/F? \nDoes the string \"%s\" have prefix %s? "</span>, str, <span class="hljs-string">"Th"</span>)
    fmt.Printf(<span class="hljs-string">"\n%t\n\n"</span>, strings.HasPrefix(str, <span class="hljs-string">"Th"</span>))    <span class="hljs-comment">// Finding prefix</span>

    fmt.Printf(<span class="hljs-string">"Does the string \"%s\" have suffix %s? "</span>, str, <span class="hljs-string">"ting"</span>)
    fmt.Printf(<span class="hljs-string">"\n%t\n\n"</span>, strings.HasSuffix(str, <span class="hljs-string">"ing"</span>))  <span class="hljs-comment">// Finding suffix</span>
}
</code></pre>
<p><a href="https://go.dev/play/p/OiVccenFYBa">Run code live here</a></p>
<p>Output:</p>
<pre><code>T/F? 
Does the string <span class="hljs-string">"Hashnode is a very easy tool to use for blogging"</span> have prefix Th? 
<span class="hljs-literal">false</span>

Does the string <span class="hljs-string">"Hashnode is a very easy tool to use for blogging"</span> have suffix ting? 
<span class="hljs-literal">true</span>
</code></pre><p>From the output above, the function <code>HasPrefix</code> checks whether the string in its first parameter starts with the <code>Th</code>. The function <code>HasSuffix</code> does the opposite of that, it checks the end of the string. The <code>HasPrefix</code> function returns <code>false</code> because the string in variable <code>str</code> doesn't start with <code>Th</code>. While <code>HasSuffix</code> returned <code>true</code> because the string <code>str</code> ends with <code>ing</code>.</p>
<p>The above methods show a simple way to test what starts and ends any string.</p>
<h3 id="heading-indexing-a-string">Indexing a string</h3>
<p>For beginners, indexing a string in Go for the first time will seem weird. When you index a string in Go you get a rune. The Go language defines the word rune as an alias for the type int32. <a href="https://go.dev/blog/strings">Read more about string in Go</a></p>
<p>Take the following code sample as an example;</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> str <span class="hljs-keyword">string</span> = <span class="hljs-string">"Hashnode is a very easy tool to use for blogging"</span>
    fmt.Println(str[<span class="hljs-number">0</span>])
}
</code></pre>
<p><a href="https://go.dev/play/p/gdFkhGA5odB">Run code live here</a></p>
<p>Output</p>
<pre><code><span class="hljs-number">72</span>
</code></pre><p>Converting the rune to a string gives the actual character at that index.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> str <span class="hljs-keyword">string</span> = <span class="hljs-string">"Hashnode is a very easy tool to use for blogging"</span>
    fmt.Println(<span class="hljs-keyword">string</span>(str[<span class="hljs-number">0</span>]))
}
</code></pre>
<p><a href="https://go.dev/play/p/PRn2PRv61sT">Run code live here</a></p>
<p>Output</p>
<pre><code>H
</code></pre><h3 id="heading-testing-if-a-string-contains-a-substring">Testing if a string contains a substring</h3>
<p>To check if a string contains some string, do the following</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strings"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> str = <span class="hljs-string">"I code Python, Golang, JavaScript, TypeScript and PHP"</span>
    fmt.Println(strings.Contains(str, <span class="hljs-string">"Golang"</span>))
    fmt.Println(strings.Contains(str, <span class="hljs-string">"Rust"</span>))
}
</code></pre>
<p><a href="https://go.dev/play/p/vjoYCSkhTyg">Run code live here</a></p>
<p>Output</p>
<pre><code><span class="hljs-literal">true</span>
<span class="hljs-literal">false</span>
</code></pre><p>The function <code>Contains</code> returns <code>true</code> if the second parameter is found in the first parameter. Otherwise, it returns <code>false</code>.</p>
<h3 id="heading-locating-the-index-of-a-substring-or-character-in-a-string">Locating the index of a substring or character in a string</h3>
<p>We can locate the first or last occurrence of a substring or character in a string.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"strings"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> str <span class="hljs-keyword">string</span> = <span class="hljs-string">"Hi, I'm Marc, Hi."</span>
    fmt.Printf(<span class="hljs-string">"The position of the first instance of\"Marc\" is: "</span>)
    fmt.Printf(<span class="hljs-string">"%d\n"</span>, strings.Index(str, <span class="hljs-string">"Marc"</span>)) <span class="hljs-comment">// Finding first occurence</span>
    fmt.Printf(<span class="hljs-string">"The position of the first instance of \"Hi\" is: "</span>)
    fmt.Printf(<span class="hljs-string">"%d\n"</span>, strings.Index(str, <span class="hljs-string">"Hi"</span>)) <span class="hljs-comment">// Finding first occurence</span>
    fmt.Printf(<span class="hljs-string">"The position of the last instance of \"Hi\" is: "</span>)
    fmt.Printf(<span class="hljs-string">"%d\n"</span>, strings.LastIndex(str, <span class="hljs-string">"Hi"</span>)) <span class="hljs-comment">// Finding last occurence</span>
    fmt.Printf(<span class="hljs-string">"The position of the first instance of\"Burger\" is: "</span>)
    fmt.Printf(<span class="hljs-string">"%d\n"</span>, strings.Index(str, <span class="hljs-string">"Burger"</span>)) <span class="hljs-comment">// Finding first occurence</span>
    fmt.Printf(<span class="hljs-string">"%d\n"</span>, strings.IndexRune(str, <span class="hljs-string">'H'</span>))  <span class="hljs-comment">// Finding first occurence</span>
}
</code></pre>
<p><a href="https://go.dev/play/p/hYHtGf04EHX">Run code live here</a></p>
<p>Output</p>
<pre><code>The position <span class="hljs-keyword">of</span> the first instance <span class="hljs-keyword">of</span><span class="hljs-string">"Marc"</span> is: <span class="hljs-number">8</span>
The position <span class="hljs-keyword">of</span> the first instance <span class="hljs-keyword">of</span> <span class="hljs-string">"Hi"</span> is: <span class="hljs-number">0</span>
The position <span class="hljs-keyword">of</span> the last instance <span class="hljs-keyword">of</span> <span class="hljs-string">"Hi"</span> is: <span class="hljs-number">14</span>
The position <span class="hljs-keyword">of</span> the first instance <span class="hljs-keyword">of</span><span class="hljs-string">"Burger"</span> is: <span class="hljs-number">-1</span>
<span class="hljs-number">0</span>
</code></pre><p><code>Index</code> returns the index of the first instance of the second parameter in the first parameter. <code>LastIndex</code> searches from the end of the string, returning the index of the last occurrence of the character or substring in the searched string. IndexRune returns the index of the first instance of the Unicode code point <code>'H'</code> in the string <code>str</code>.</p>
<h2 id="heading-to-be-continued">To be continued</h2>
<p>Hope you learned something new today!. This part of the String series focuses on how you can test the values of a string in Go. You can practice more of the functions covered in this tutorial. To master and do more practice check out the Strings module <a href>documentation</a>. Learn on your own how to use <code>strings.Count</code> to count the number of occurences of a character or substring in a string.</p>
<p>In the next part, we would look at ways a string can be manipulated in Go. Thanks for reading. </p>
]]></content:encoded></item><item><title><![CDATA[Building a Lightweight Web Server with Golang]]></title><description><![CDATA[Let's have some fun with Golang by building a simple website application server. Golang is a very robust and fast programming language. We will build this purely with only Golang no extra dependencies.
To follow this tutorial, you need to have basic ...]]></description><link>https://blog.covenlabs.space/building-a-lightweight-web-server-with-golang</link><guid isPermaLink="true">https://blog.covenlabs.space/building-a-lightweight-web-server-with-golang</guid><category><![CDATA[golang]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sat, 01 Oct 2022 12:41:26 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664627423595/hN8TZQbc_.png" alt="1-web-server-3edc7d64437aeed2116ff819898d2d4d.png" /></p>
<p>Let's have some fun with Golang by building a simple website application server. Golang is a very robust and fast programming language. We will build this purely with only Golang no extra dependencies.</p>
<p>To follow this tutorial, you need to have basic knowledge of Golang programming. Visit <a target="_blank" href="https://go.dev/tour/welcome/1">Go Tour</a> to quickly get a basic understanding of programming Golang.</p>
<p>The goal is to write a Go program that serves HTML, CSS, JS, and static files from a root directory. For example, if we have a directory structure like below</p>
<pre><code>project
├── website
│   ├── index.html
│   ├── file1.html
|   ├── file2.html
|   └── assets
│       ├── style.css
│       └── script.js
└── main.go
</code></pre><p>When we run main.go with port <code>8000</code>, we would be able to visit the following URLs</p>
<ul>
<li>http://localhost:8000/</li>
<li>http://localhost:8000/index.html</li>
<li>http://localhost:8000/file1.html</li>
<li>http://localhost:8000/assets/style.css</li>
</ul>
<p>The website directory is the root directory. We can place all our HTML files and static files in that directory. Then we can access them with the URL <code>http://localhost:8000/</code>. This URL represents our root directory, <code>website</code>. While building the web server we can decide</p>
<ul>
<li>which directory to be the root folder,</li>
<li>what the URL should be, and</li>
<li>how files are processed.</li>
</ul>
<h2 id="heading-why-golang">Why Golang</h2>
<p>Languages like Python requires developers to depend on web frameworks like Django or Flask to build web applications. Golang has a lot of built-in functionality for building web apps, like;</p>
<ul>
<li>Handling routes,</li>
<li>Database connections,</li>
<li>Template rendering,</li>
<li>Testing,</li>
<li>and more.</li>
</ul>
<p>Golang requires fewer to no dependencies installed to build a website application.</p>
<h2 id="heading-get-set-go">Get set, Go! 🛩️</h2>
<h3 id="heading-install-golang">Install Golang</h3>
<p>Install Golang by visiting <a target="_blank" href="https://go.dev/learn/">Go.dev</a> to install Golang on your machine. The installation binaries are available for any Operating System (Windows, Mac, Linux, etc.).</p>
<h3 id="heading-setup-project-directory">Setup project directory</h3>
<p>To setup our project directory, </p>
<ul>
<li>create a new directory/folder for the web server project,</li>
<li>create a file named <code>main.go</code>, and</li>
<li>open the file in any editor of choice.</li>
</ul>
<h3 id="heading-lets-build">Let's build 💪🏽</h3>
<p>Paste the following content in the <code>main.go</code> file.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main


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

}
</code></pre>
<p>Every Go program is made up of packages and Programs start running in package <code>main</code>. The function <code>main</code> is executed when we run our <code>main.go</code> file or its build.</p>
<p>Create a function called <code>ServeStatic</code> that registers the pattern <code>/</code> to a <code>handler function</code> that serves static contents in the root folder. The pattern is registered in the default <code>DefaultServeMux</code>. We could also create our own <a target="_blank" href="https://pkg.go.dev/net/http?utm_source=gopls#ServeMux">ServeMux</a>, and register patterns to it. We could have multiple ServeMux depending on your requirement.</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"net/http"</span>

<span class="hljs-comment">// Provides handler function to read and respond with static files</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">ServeStatic</span><span class="hljs-params">()</span></span> {
    h1 := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        <span class="hljs-comment">// code here</span>
    }
    http.HandleFunc(<span class="hljs-string">"/"</span>, h1)
}
</code></pre>
<p>Take a look at <code>http.HandleFunc("/", h1)</code>, the first parameter is the pattern, and the second parameter is the handler function. http.HandleFunc registers the pattern, <code>/</code>, to the handler function, <code>h1</code>.</p>
<p>DefaultServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.</p>
<p>We use the pattern "/" because it matches all paths not matched by other registered patterns, not just the URL with Path == "/". Meaning the pattern, "/" matches URLs paths</p>
<ul>
<li>/</li>
<li>/anything</li>
<li>/a.html</li>
<li>/a/b/c.html</li>
<li>/a/b/c/.../z.html</li>
</ul>
<p>When we visit paths like <code>/blog/posts/web-developments/how-to-build-a-website.html</code> our handler function will be executed, because its pattern "/" matches it.</p>
<p>The handle function is executed with two parameters, a http.ResponseWriter and a *<a target="_blank" href="https://pkg.go.dev/net/http?utm_source=gopls#Request">http.Request</a>. We can use the ResponseWriter to construct an HTTP response. The Request represents an HTTP request received from the server. It contains data like URL path, Request headers, Request body, the Request method, etc.</p>
<p>The static file path can be extracted from the URL Path, then we can get the content from the file path and use it to construct an HTTP response with our ResponseWriter.</p>
<p>Let's create a function to construct the file path relative to a root folder called <code>website</code>. We can use any directory as our root folder. I am using this for simplicity.</p>
<pre><code class="lang-go"><span class="hljs-comment">// Gets the relative path of the requested path, making `website` the base path</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">RelPath</span><span class="hljs-params">(path <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"website"</span> + path
}
</code></pre>
<p>This is my directory structure,</p>
<pre><code>go_server
├── website
│   ├── index.html
│   ├── about.html
|   ├── main.css
|   └── contact.html
└── main.go
</code></pre><p>Therefore, if the path is <code>/about.html</code>, the file path relative to the root folder, website, is <code>website/about.html</code>.</p>
<p>For example, if our directory structure is like the below.</p>
<pre><code>go_server
├── website
│   └── public
│       ├── index.html
│       ├── about.html
|       ├── main.css
|       └── contact.html
└── main.go
</code></pre><p>If we wanted the public folder to be the root folder, then our <code>RelPath</code> function should look like this</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">RelPath</span><span class="hljs-params">(path <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"website/public"</span> + path
}
</code></pre>
<p>The complete ServeStatic function is below.</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"net/http"</span>

<span class="hljs-comment">// Provides handler function to read and respond with static files</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">ServeStatic</span><span class="hljs-params">()</span></span> {
    h1 := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        path := RelPath(r.URL.Path)
        http.ServeFile(w, r, path)
    }
    http.HandleFunc(<span class="hljs-string">"/"</span>, h1)
}
</code></pre>
<p><a target="_blank" href="https://pkg.go.dev/net/http?utm_source=gopls#ServeFile">http.ServeFile</a> is a function that replies to the request with the contents of the named file or directory. After the execution of <code>RelPath(r.URL.Path)</code>, the variable, path, will be a file path relative to the root folder. The program is able to access this folder because the <code>main.go</code> file is in the same directory as the root folder.</p>
<p>If the path does not exist, a <code>404 page not found</code> response is written to the ResponseWriter. Read more on <a target="_blank" href="https://pkg.go.dev/net/http?utm_source=gopls#ServeFile">http.ServeFile</a> to see how it handles paths.</p>
<p>Finally, We need to listen to requests on a <a target="_blank" href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP</a> network address.</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"log"</span>

<span class="hljs-comment">// Listen and serve port</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">StartServer</span><span class="hljs-params">(addr <span class="hljs-keyword">string</span>)</span></span> {
    log.Printf(<span class="hljs-string">"Starting server listening on: http://localhost:%v"</span>, addr)
    log.Fatal(http.ListenAndServe(<span class="hljs-string">":"</span>+addr, <span class="hljs-literal">nil</span>))
}
</code></pre>
<p>StartServer function accepts a network address, addr, to use with <a target="_blank" href="https://pkg.go.dev/net/http?utm_source=gopls#ListenAndServe">http.ListenAndServe</a>. The ListenAndServe function accepts an addr, string, and a handler, http.Handler. </p>
<p>ListenAndServe listens to the TCP network address, addr, and then calls Serve with the handler to handle requests on incoming connections. The handler is typically nil, in which case the DefaultServeMux is used. You can create your own ServeMux to use here instead.</p>
<p>For example, if addr is <code>6500</code>, then the URL will be <code>http://localhost:6500</code>. So any time a request is sent to the URL, the DefaultServeMux handles it.</p>
<p>Now we update our <code>main</code> function to execute the <code>ServeStatic</code> and <code>StartServer</code> functions.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {

    ServeStatic()
    StartServer(<span class="hljs-string">"8000"</span>)

}
</code></pre>
<p>Here we used <code>8000</code> as our TCP network address, therefore our URL will be <code>http://localhost:8000</code>.</p>
<p>This is what the complete <code>main.go</code> file should look like</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>
)

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

    ServeStatic()
    StartServer(<span class="hljs-string">"8000"</span>)

}

<span class="hljs-comment">// Listen and serve port</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">StartServer</span><span class="hljs-params">(addr <span class="hljs-keyword">string</span>)</span></span> {
    log.Printf(<span class="hljs-string">"Starting server listening on: http://localhost:%v"</span>, addr)
    log.Fatal(http.ListenAndServe(<span class="hljs-string">":"</span>+addr, <span class="hljs-literal">nil</span>))
}

<span class="hljs-comment">// Gets the relative path of the requested path, making `website` the base path</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">RelPath</span><span class="hljs-params">(path <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"website"</span> + path
}

<span class="hljs-comment">// Provides handler function to read and respond with static files</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">ServeStatic</span><span class="hljs-params">()</span></span> {
    h1 := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
        path := RelPath(r.URL.Path)
        http.ServeFile(w, r, path)
    }
    http.HandleFunc(<span class="hljs-string">"/"</span>, h1)
}
</code></pre>
<p>Check out this <a target="_blank" href="https://github.com/devvspaces/golang_web_server">repo</a> for the complete project. It has sample HTML and CSS files to use with the web server.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/devvspaces/golang_web_server">https://github.com/devvspaces/golang_web_server</a></div>
<h2 id="heading-conclusion">Conclusion 🎯</h2>
<p>You can do much with Golang's standard HTTP <a target="_blank" href="https://pkg.go.dev/net/htttp">library</a>. For sample projects, you can build a website form, polling website, todo website, CRUD website, Rest APIs, and more</p>
<p>The best place to learn and get more information about Golang libraries &amp; packages is their <a target="_blank" href="https://pkg.go.dev/">documentation</a>. It has robust documentation with examples.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wt570kpytt4hsctjxwuq.gif" alt="Image description" /></p>
]]></content:encoded></item><item><title><![CDATA[Learn Python Decorators from Basic to Pro in 10 mins]]></title><description><![CDATA[Let's learn about python decorators. This is one of the patterns I love to use in python and It is widely used by senior programmers out there.
What are decorators 🤔
A decorator in python is a design pattern that allows us to extend the functionalit...]]></description><link>https://blog.covenlabs.space/learn-python-decorators-from-basic-to-pro-in-10-mins</link><guid isPermaLink="true">https://blog.covenlabs.space/learn-python-decorators-from-basic-to-pro-in-10-mins</guid><category><![CDATA[#week4]]></category><category><![CDATA[#4weeks4articles]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[python beginner]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Sun, 11 Sep 2022 21:25:12 GMT</pubDate><content:encoded><![CDATA[<p>Let's learn about python decorators. This is one of the patterns I love to use in python and It is widely used by senior programmers out there.</p>
<h1 id="heading-what-are-decorators">What are decorators 🤔</h1>
<p>A decorator in python is a design pattern that allows us to extend the functionality of a function without modifying the function itself.  We can do this by wrapping the function we want to extend functionality to with another function. It is not complex at all, it's a very simple pattern. On the low level, we are just passing a function as an argument to another function which will return a function we can call to call the function passed as an argument in the first place.</p>
<h2 id="heading-patterns-behind-a-decorator">Patterns behind a decorator</h2>
<p>In python, we can nest functions. Inner functions can access the outer scope of the enclosing function. Meaning that if we define a variable in the enclosed function, the inner function can have access to it. This pattern is called Closure. This concept is very important, it is the core concept of python decorators. This concept is also used in other languages out there, including JavaScript, Golang, and more.</p>
<h1 id="heading-coding-decorators">Coding Decorators</h1>
<p>Let's dive into some python codes which will help us understand all those theories and jargon above.</p>
<h2 id="heading-functional-decorators">Functional decorators</h2>
<p>Assuming we have a function <code>calculate_number</code> that returns a number <code>5</code>, but then some requirements came up that we needed to increase the output of that function by <code>1</code>, now we can create another function <code>increase_number</code> that can help us do that. This is just an example we will cover complex use cases towards the end of the tutorial.</p>
<p>We have our function that returns the number</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>
</code></pre>
<p>We have another function here, let's pay close attention to this function</p>
<pre><code class="lang-python"><span class="hljs-comment"># Decorator to increase function output by one</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
        <span class="hljs-string">"""
        Calls the function passed as an argument in the outer
        scope and adds one to the output
        """</span>
        <span class="hljs-keyword">return</span> func() + <span class="hljs-number">1</span>

    <span class="hljs-keyword">return</span> wrapper
</code></pre>
<p>So let's break this down;</p>
<ul>
<li><p>Take a look at the <code>increase_number</code> function, </p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
      ...

  <span class="hljs-keyword">return</span> wrapper
</code></pre>
<p>We need to pass a function as an argument to this function. A function is defined in the function <code>increase_number</code> called <code>wrapper</code>, we can call it any name, and the function is returned without calling it. Meaning that if <code>increase_number</code> function is called, it's going to return a function as the response, <code>wrapper</code>, which can also be called.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Pass `calculate_number` as an argument</span>
var_a = increase_number(calculate_number)
<span class="hljs-comment"># Call the function returned above</span>
inner_function_response = var_a()
</code></pre>
<p><code>var_a</code> from above will contain the <code>wrapper</code> function waiting to be called. Then it was called and its return value is assigned to the variable <code>inner_function_response</code>.</p>
</li>
<li><p>Inside the nested function <code>wrapper</code> above, we called the function passed as an argument to the enclosing function and add <code>1</code> to it and return the answer,</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
  <span class="hljs-string">"""
  Calls the function passed as an argument in the outer
  scope and adds one to the output
  """</span>
  <span class="hljs-keyword">return</span> func() + <span class="hljs-number">1</span>
</code></pre>
<p>We could call that function passed as an argument because it is in the scope of the enclosing function and the nested function as access to the outer scope. This concept is called Closure. We can also do something before we call the function and after we call the function. Also, do something before we define the function <code>wrapper</code> and after we define it.
Try the example below;</p>
</li>
</ul>
<pre><code class="lang-python">  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">outer_function</span>(<span class="hljs-params">func</span>):</span>

      print(<span class="hljs-string">'Before defining inner function'</span>)

      <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner_function</span>():</span>

          print(<span class="hljs-string">'Do something before calling function'</span>)

          func()  <span class="hljs-comment"># Call function passed as argument in outer function</span>

          print(<span class="hljs-string">'Do something after calling function'</span>)

      print(<span class="hljs-string">'Do something before returning the inner function'</span>)

      <span class="hljs-keyword">return</span> inner_function


  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sample</span>():</span>
      print(<span class="hljs-string">'I was decorated'</span>)


  outer_function(sample)()
</code></pre>
<p>Output</p>
<pre><code class="lang-txt">Before defining inner function
Do something before returning the inner function
Do something before calling function
I was decorated
Do something after calling function
</code></pre>
<p>Full code: Increasing the number decorator</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
        <span class="hljs-keyword">return</span> func() + <span class="hljs-number">1</span>

    <span class="hljs-keyword">return</span> wrapper


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>


var_a = increase_number(calculate_number)
inner_function_response = var_a()
print(inner_function_response)
</code></pre>
<p>Running the above code should output <code>6</code>.</p>
<p>To summarize what is happening again;</p>
<ul>
<li>the function <code>calculate_number</code> returns 5,</li>
<li>the function <code>increase_number</code> is a decorator, it takes in a function and wraps it with another function, then returns the wrapper, allowing us to manipulate the return value of the function passed as an argument which is going to be function <code>calculate_number</code>.</li>
<li>the nested function, <code>wrapper</code>, inside the function <code>increase_number</code> calls the function passed to function <code>increase_number</code> and adds 1 to the return value, then returns the answer.</li>
<li>the nested function, <code>wrapper</code>, is returned by the function <code>increase_number</code>, so that we can do something with it, most of the time we end up just calling it like a normal function as we did here with <code>var_a</code>.  I said most of the time because we could also pass the returned function in variable <code>var_a</code> as an argument to another decorator, function.</li>
</ul>
<h2 id="heading-pythonic-syntax-of-using-decorators">Pythonic syntax of using decorators</h2>
<p>Decorators are used a lot in python, there are even built-in decorators like staticmethod, classmethod, property, and more. So there is a pythonic syntax you can use to decorate a function. Imagine we wanted to apply multiple decorators to the function <code>calculate_number</code> in the code above using the current way, it would be too complex for you or another person to understand the code when there is a bug in the code or just reading through the code.</p>
<p>Pythonic Code: Increasing the number</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
        <span class="hljs-keyword">return</span> func() + <span class="hljs-number">1</span>

    <span class="hljs-keyword">return</span> wrapper


<span class="hljs-meta">@increase_number</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>


print(calculate_number())
</code></pre>
<p>This is beautiful, I love this syntax. What happened here is simple, we decorated the function <code>calculate_number</code> with function  <code>increase_number</code> by placing it just above the function <code>calculate_number</code> with the <code>@</code> symbol before it. This tells python that this is a decorator, so when this function <code>calculate_number</code> is called, it automatically does the passing of the function to the decorator and calls the wrapper function. So now we can just call the function itself and it will get decorated. Now we can easily add multiple decorators to a function without making it too complex to understand.</p>
<h2 id="heading-multiple-decorators">Multiple decorators</h2>
<p>Multiple decorators can be applied to a single function, by just stacking the decorators on top of each other using the decorator syntax <code>@decorator_function</code>.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">split_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>():</span>
        <span class="hljs-keyword">return</span> func().split()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">uppercase_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>():</span>
        <span class="hljs-keyword">return</span> func().upper()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-meta">@split_string</span>
<span class="hljs-meta">@uppercase_string</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak_python</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I love speaking Python"</span>

print(speak_python())
</code></pre>
<p>Output</p>
<pre><code class="lang-txt">['I', 'LOVE', 'SPEAKING', 'PYTHON']
</code></pre>
<p>The first question that might come to your mind is, what is the order of how this decorator is applied to this function when it is called? The answer is it is from bottom to top, <code>uppercase_string</code> then <code>split_string</code>. So from the output above you can tell that the string was first converted to uppercase then it was split returning a list of uppercased strings.</p>
<p>You can also test it out, try switching the positions of the decorators, and place <code>@uppercase_string</code> on top of <code>@split_string</code>.</p>
<p>Code</p>
<pre><code class="lang-python"><span class="hljs-meta">@uppercase_string</span>
<span class="hljs-meta">@split_string</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak_python</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I love speaking Python"</span>
</code></pre>
<p>Output</p>
<pre><code class="lang-text">...
AttributeError: 'list' object has no attribute 'upper'
</code></pre>
<p>From the output above, there was an error because the <code>@uppercase_string</code> decorator was trying to call <code>upper</code> method on a list. This happened because the <code>@split_string</code> decorator split the string first returning a list of strings, then the  <code>@uppercase_string</code> decorator tried to apply the <code>upper</code> method on that list which is impossible as python lists do not have an <code>upper</code> method built-in.</p>
<h2 id="heading-decorating-functions-that-accept-arguments">Decorating functions that accept arguments</h2>
<p>If our functions accept arguments, no need to worry, we just have to update our decorator to accept the arguments and pass them to the decorated function when calling it.
Let's modify our <code>speak_python</code> function above to accept a language as an argument, format it with the string, and return it.</p>
<p>Bad Code:</p>
<pre><code class="lang-python"><span class="hljs-meta">@split_string</span>
<span class="hljs-meta">@uppercase_string</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak_language</span>(<span class="hljs-params">language</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"I love speaking <span class="hljs-subst">{language}</span>"</span>


print(speak_language(<span class="hljs-string">"Python"</span>))
</code></pre>
<p>Output:</p>
<pre><code class="lang-txt">...
TypeError: inner() takes 0 positional arguments but 1 was given
</code></pre>
<p>We got the error because the argument <code>Python</code> is being passed to the inner functions of our decorators, but those inner functions don't take any arguments, positional or keyword arguments. So we have to update the decorators to make sure the inner functions take in arguments.</p>
<p>Good code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">split_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>(<span class="hljs-params">a</span>):</span>
        <span class="hljs-keyword">return</span> func(a).split()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">uppercase_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>(<span class="hljs-params">a</span>):</span>
        <span class="hljs-keyword">return</span> func(a).upper()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-meta">@split_string</span>
<span class="hljs-meta">@uppercase_string</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak_language</span>(<span class="hljs-params">language</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"I love speaking <span class="hljs-subst">{language}</span>"</span>


print(speak_language(<span class="hljs-string">"Python"</span>))
</code></pre>
<p>Output:</p>
<pre><code class="lang-txt">['I', 'LOVE', 'SPEAKING', 'PYTHON']
</code></pre>
<p>Now it's working, what happened;</p>
<ul>
<li>the inner functions now accept an argument,</li>
<li>then the argument is passed to the decorated function.</li>
</ul>
<h2 id="heading-general-decorators">General Decorators</h2>
<p>We can also create a decorator that accepts any amount of arguments, positional and keyword arguments, and passes them to the decorated function.
Say we updated our <code>speak_language</code> function to accept more arguments, we would have to update all our decorators to accept those arguments. Imagine we have a complex codebase with a lot of decorators, it would be hard to update all of them. So we should make sure our decorators can handle multiple arguments in the future.</p>
<p>Best Code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">split_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        <span class="hljs-keyword">return</span> func(*args, **kwargs).split()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">uppercase_string</span>(<span class="hljs-params">func</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inner</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        <span class="hljs-keyword">return</span> func(*args, **kwargs).upper()
    <span class="hljs-keyword">return</span> inner


<span class="hljs-meta">@split_string</span>
<span class="hljs-meta">@uppercase_string</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">speak_language</span>(<span class="hljs-params">word, language</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"I <span class="hljs-subst">{word}</span> speaking <span class="hljs-subst">{language}</span>"</span>


print(speak_language(<span class="hljs-string">"hate"</span>, <span class="hljs-string">"Python"</span>))
</code></pre>
<p>Output:</p>
<pre><code class="lang-txt">['I', 'HATE', 'SPEAKING', 'PYTHON']
</code></pre>
<p><em>args and *</em>kwargs allow you to pass multiple arguments or keyword arguments to a function. So we used it in the inner functions to accept any number of arguments and also pass them all to the decorated function. Now no matter how many arguments are passed to the <code>speak_language</code> function in the future, we don't need to update the decorators. One less problem to think about. 😁</p>
<p><a target="_blank" href="https://realpython.com/python-kwargs-and-args">Learn more about <em>args and *</em>kwargs</a></p>
<h2 id="heading-decorator-factory">Decorator Factory</h2>
<p>Let's go back to our increase_number function
Code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
        <span class="hljs-keyword">return</span> func() + <span class="hljs-number">1</span>

    <span class="hljs-keyword">return</span> wrapper


<span class="hljs-meta">@increase_number</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>


print(calculate_number())
</code></pre>
<p>This decorator only increases this number by <code>1</code>, what if we want to apply an increase by 10? We can edit the decorator to increase it by 10. What if we have another function that needs a decorator to increase it by 5, we can create another decorator like <code>increase_number</code> that increases it by 5. This is not good because we are repeating code, we should try not to repeat codes anywhere possible because if there turns out to be a bug in the code we will have to change all places where the code has been replicated.</p>
<p>It is also possible with decorators. With the understanding of Closures, we know that a nested function has access to the scope of the outer function. Then we can create a function that returns a decorator. Doing this means if we pass an argument to the function creating the decorator, the decorator would have access to the arguments passed to its outer function and the inner function of the decorator should have access to these arguments too. Let's take a look at the code below.</p>
<p>Code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">A</span>(<span class="hljs-params">arg1</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">B</span>():</span>
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">C</span>():</span>
            <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">D</span>():</span>
                <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">E</span>():</span>
                    print(arg1)
                <span class="hljs-keyword">return</span> E
            <span class="hljs-keyword">return</span> D
        <span class="hljs-keyword">return</span> C
    <span class="hljs-keyword">return</span> B


A(<span class="hljs-string">"Good Python"</span>)()()()()
</code></pre>
<p>Output:</p>
<pre><code class="lang-txt">Good Python
</code></pre>
<p>I think with this piece of code, I have done justice to the fact that nested functions always have access to the outer function scope. Function <code>E</code> was nested four levels down, but still has access to the scope of function <code>A</code>.</p>
<p>This is the same idea behind a decorator factory, a function that returns a decorator. So to make the applied increase dynamic, we can create a function that accepts the number to increase by as an argument and then return a decorator which has access to this number.
Code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">apply_increase</span>(<span class="hljs-params">increase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">increase_number</span>(<span class="hljs-params">func</span>):</span>

        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span>():</span>
            <span class="hljs-keyword">return</span> func() + increase

        <span class="hljs-keyword">return</span> wrapper

    <span class="hljs-keyword">return</span> increase_number


<span class="hljs-meta">@apply_increase(10)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>


<span class="hljs-meta">@apply_increase(1)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">myother_number</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>


print(calculate_number())
print(myother_number())
</code></pre>
<p>Output:</p>
<pre><code class="lang-txt">15
2
</code></pre>
<p>The <code>apply_increase</code> function accepts the number as an argument, then returns the decorator. Since the decorator function returned for each of the functions above has access to the scope of their outer functions, we get unique decorators because the numbers in <code>apply_increase(10)</code> and <code>apply_increase(1)</code> are different. For both of the decorators returned, their <code>increase</code> argument will be different.</p>
<h2 id="heading-conclusion">Conclusion 👍</h2>
<p>Decorator is a very amazing pattern in python, with it we can extend the functionality of the wrapped function. We have covered a lot in this article, but there are other things we haven't covered. Class decorators, method decorators, and python functools module will be covered in another article. Thanks for reading, Arigato. ✌️</p>
<p>If you love this article, you can give this article likes and 10 reactions, comment below if you have any questions or views, and follow me for more updates on Software programming.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662930969832/HyR_7ryqw.gif" alt="KissThankYouGIF.gif" /></p>
]]></content:encoded></item><item><title><![CDATA[Building Server Eyes: A simple GUI for Server and CI/CD management]]></title><description><![CDATA[It's Netrobe here again. I would love to introduce you to an open-source project I built using Django, Python, and many amazing tools out there, that helped my team members at Spacepen deploy web products built with React, PHP, HTML, and Python witho...]]></description><link>https://blog.covenlabs.space/building-server-eyes-a-simple-gui-for-server-and-cicd-management</link><guid isPermaLink="true">https://blog.covenlabs.space/building-server-eyes-a-simple-gui-for-server-and-cicd-management</guid><category><![CDATA[#week3]]></category><category><![CDATA[4articles4weeks]]></category><category><![CDATA[Python]]></category><category><![CDATA[#4weeks4articles]]></category><category><![CDATA[python projects]]></category><dc:creator><![CDATA[Ayomide Ayanwola]]></dc:creator><pubDate>Fri, 02 Sep 2022 09:03:45 GMT</pubDate><content:encoded><![CDATA[<p>It's Netrobe here again. I would love to introduce you to an open-source project I built using Django, Python, and many amazing tools out there, that helped my team members at Spacepen deploy web products built with React, PHP, HTML, and Python without the need of a Cloud Operations Engineer, Netrobe. It was an amazing project, it allowed frontend designers and backend developers to set auto-deployment on GitHub repositories, which automatically redeploys the project to a production server from GitHub on every update on the repository. This helped to increase product delivery time and iteration testing while in a production environment.</p>
<h2 id="heading-project">Project</h2>
<p>Available on <a target="_blank" href="https://github.com/devvspaces/server_eyes/">GitHub</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/devvspaces/server_eyes">https://github.com/devvspaces/server_eyes</a></div>
<p>It's an open-source project and open to contributions.</p>
<h2 id="heading-problem-statement">Problem statement 😖</h2>
<p>There are several team members and just a DevOps engineer, these team members are mostly frontend developers that are placed in separate groups to work on separate projects. Some of the team members are backend developers. What they all have in common is that they need to deploy their projects to the business server so they can test in production with no hassle. Mostly this deployments are iterations, for example, <code>build -&gt; deploy -&gt; test -&gt; debug -&gt; build …</code>. These deployments will need the DevOps engineer, Netrobe, to always be available which is usually stressful for both him and them. Mind you, there is no time for each developer to learn about tools that can be used for CI/CD, we just needed a simple way for them to deploy without stress.</p>
<blockquote>
<p>No one hates stress more than I do, I like automating everything. If it's possible to automate a certain task, I'm going to do it. 😁</p>
</blockquote>
<h2 id="heading-solution-statement">Solution statement 💪🏽</h2>
<p>Now the solution is to give team members just the ability to deploy and test each product on the server without the need to wait for the DevOps engineer to be available all the time. They would not even touch the server but deploy and iterate new products seamlessly in production through a friendly web interface.</p>
<h2 id="heading-solution-chart">Solution Chart 😎</h2>
<h3 id="heading-ssh-connection">SSH Connection 🎯</h3>
<p>I planned to use the python <a target="_blank" href="https://pypi.org/project/paramiko/">Paramiko</a> module to connect to the server through <a target="_blank" href="https://en.wikipedia.org/wiki/Secure_Shell">SSH (Secure Shell)</a>. This allows me to automatically send commands to the server with SSH securely, for example, commands to deploy Nginx or Apache websites depending on the web server the connected server is configured to use.</p>
<h3 id="heading-github-api">GitHub API 🎯</h3>
<p>Also, I used <a target="_blank" href="https://docs.github.com/en/rest">GitHub API</a> and <a target="_blank" href="https://docs.github.com/en/rest/webhooks">GitHub Webhooks</a> to automatically redeploy deployed websites on the server on every new update made to deployed repositories. Logged-in user can connect their GitHub account to the software, and configure repositories that can be deployed and those that should not be deployed. With this implementation, they can easily select a repository they want to deploy to production.</p>
<h3 id="heading-linode-api">Linode API 🎯</h3>
<p>Lastly, <a target="_blank" href="https://www.linode.com/">Linode</a> was the VPS provider used by the company, so I used <a target="_blank" href="https://www.linode.com/docs/api/">Linode's API</a>, which is very robust, to automatically create, update and delete domain records when deploying new repositories. Meaning, that when a user is about to deploy a repository, they can set the domain name for the product they want to deploy right there. This allows them to easily deploy different versions of products to production with different domain names.</p>
<h2 id="heading-how-did-i-come-up-with-this-solution">How did I come up with this solution</h2>
<p>First of all, this is might not the best solution for this project. I knew I would need to talk to the server automatically to do some things. I use SSH almost every day to connect to several servers, so I knew all I needed to do was find a way to do this using python. During my research, I got to know about <code>Paramiko</code>. It was very bad, there was no good documentation there at all. I learned more about finding resources and codes online. I had to do a good amount of searches on google and narrow down my search results to important ones by adding important keywords. This is one of the best skills to have, just keep on practicing it daily. I have never had a reason to ask a question on StackOverflow myself even when I hit complex problems, I will keep on looking for some kind of clues on the web.</p>
<p>Also, as for the GitHub API, I just searched <code>GitHub API</code> and <code>GitHub Webhook</code> just to know if they had an API and webhook. The documentation for their APIs is pretty easy to use. I searched for Linode's API too, it was nice, it's even possible to launch new servers with their API. I learned how to work with multiple APIs easily in a pythonic way. I utilized the <code>DRY</code> pattern and created a base API class that I can inherit later in other API-specific classes for Linode and GitHub. This way made it easy for me to not repeat header authorization, get, post, and other methods in both classes. With this current implementation, if I want to add GoDaddy's API, Namecheap's API, or any API, it would be easy for me to get started with it, and help me focus on consuming the API instead of reconstructing the wheel.</p>
<p>Furthermore, I learned more commands for Linux Bash when using SSH, I had to automatically run some complex commands, for example, finding files, checking if files exist, creating files, moving and copying files, reading log files from server to website, filtering log files and many more. I had to do a lot of complex things. I had to learn learn and use other design patterns like  <code>Composition over Inheritance, Bridge Pattern, Adaptor Pattern, Singleton Patterns</code> to create reusable components. I had to build dynamic Apache and Nginx configurations, which depend on the domain name, deploy folder, and logs.</p>
<h2 id="heading-summary">Summary</h2>
<p>Most of the things I learned are;</p>
<ul>
<li>Linux commands</li>
<li>Bash Scripting</li>
<li>Using the Python Requests module: authorization with headers</li>
<li>Working with APIs</li>
<li>Design Patterns: Composition over Inheritance, Bridge Pattern, Adaptor Pattern, Singleton Patterns</li>
<li>Redis Database: used this for fast in-memory caching and message broker. The message broker part was to help the Django sand manage asynchronous deployment processes.</li>
<li>Python OS module, it's amazing <a target="_blank" href="https://docs.python.org/3/library/pathlib.html">Pathlib</a> module, JSON module, and more.</li>
<li>Python Paramiko module</li>
<li>Python Generators</li>
<li>GitHub API and GitHub Webhooks: read and track repositories</li>
<li>Consuming webhooks properly</li>
<li>Linode API: managing domain records</li>
<li>Apache and Nginx: webservers for deploying the repositories on the connected servers.</li>
<li>UML diagrams and Flowcharts: Helped me know to understand the process before doing justice with python.</li>
</ul>
<p>These are some of the tools I learned while building the project but did not use for it.</p>
<ul>
<li><a target="_blank" href="https://www.rabbitmq.com/">GitHub Actions</a>: setup CI/CD for your repositories. Build, Test, Deploy. I later used this knowledge for other projects, it's an amazing tool to learn. Very good when collaborating with other developers, you can easily set up tests to run anytime a branch is to be merged with the master branch. It was after I learned this tool I found out that most big open source projects out there are using it, they tend to collaborate with thousands of other developers and have to be releasing builds very frequently. <a target="_blank" href="https://docs.github.com/en/actions">Get started with GitHub Actions</a>.</li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Message_queue">Message Queues</a>: Redis is not a message queue, but it could do what I needed. Tools I got to know more about were <a target="_blank" href="https://kafka.apache.org/">Kafka</a> and <a target="_blank" href="https://www.rabbitmq.com/">RabbitMQ</a>. Message queues are excellent, and can be used when building decoupled services that need to communicate with each other.</li>
</ul>
<p>I later found some other tools that are better than Paramiko, it's hard to run sudo commands on Paramiko securely. A little tweaking in the way sudo commands are being called made it possible but in the long run it's not a secure way. It's like a hack, that module is ancient. The better tools to use instead of Paramiko are <a target="_blank" href="https://docs.fabfile.org/en/stable/getting-started.html#">Fabric</a> and <a target="_blank" href="https://docs.pyinvoke.org/en/latest/index.html">Invoke</a>. These tools are built on top of Paramiko, thanks to <a target="_blank" href="https://github.com/bitprophet">Jeff Forcier</a> for doing this. My love for open-source projects is too much. Es muy grande. I am planning to use these modules in place of Paramiko. If you want to contribute, you can contact me on <a target="_blank" href="https://github.com/devvspaces">Github</a> let's learn together. 💪🏽😁</p>
<h2 id="heading-conclusion">Conclusion ✌️</h2>
<p>There are a lot of tools out there that a developer can learn to automate this kind of stuff, but I just wanted to try it out mostly and also help my team members in the process. By doing that, I learned a lot of things in the process. Don't say someone has done it before, push yourself to the limit. When you do that, you will know you have no limit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662799591671/aisV__PFp.gif" alt="KeepGoingGIF.gif" /></p>
]]></content:encoded></item></channel></rss>