<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joshua Evuetapha</title>
    <description>The latest articles on DEV Community by Joshua Evuetapha (@joshuajee).</description>
    <link>https://dev.to/joshuajee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F610694%2F141ee5ff-39e0-4e95-91ba-a958a1304214.jpeg</url>
      <title>DEV Community: Joshua Evuetapha</title>
      <link>https://dev.to/joshuajee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joshuajee"/>
    <language>en</language>
    <item>
      <title>Ethonline 2023, my experience, challenge, and Lessons Learnt</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Wed, 08 Nov 2023 06:36:09 +0000</pubDate>
      <link>https://dev.to/joshuajee/ethonline-2023-my-experience-challenge-and-lessons-learnt-1o1p</link>
      <guid>https://dev.to/joshuajee/ethonline-2023-my-experience-challenge-and-lessons-learnt-1o1p</guid>
      <description>&lt;p&gt;So a few weeks ago, I saw that eth-online was about to start, so I hopped on, I wanted to learn more about ZKEVM and win some cool cash prizes this year I have been part of a few hackathons and I made second runner-up in both &lt;a href="https://twitter.com/hyperlaneIndia/status/1665365755360157700" rel="noopener noreferrer"&gt;Hyperlane Hyperhack&lt;/a&gt; and &lt;a href="https://devfolio.co/projects/flow-merchant-5d2e" rel="noopener noreferrer"&gt;Flow future hackathon&lt;/a&gt;, where I want about 400 USD and 6000 USD respectively.&lt;br&gt;
So I came supercharged for Eth-online, what am I to build a rock, paper, scissors game on polygon zkevm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Really? A rock, paper, scissors game onchain?
&lt;/h3&gt;

&lt;p&gt;Well, I wanted to build a very simple decentralized game in a way no one else has ever done.&lt;br&gt;
My plans were much I wanted to leverage a lot on polygon services, so why polygon zkevm? Since zkevm is way cheaper than Mainnet and transactions are faster on the ZKEVM, I saw it as an ideal place to build on-chain games, and the rock, paper, scissors game was simple enough.&lt;br&gt;
Here is how the game would work, users would earn RPS point tokens for every real person they win on-chain, you get 10 RPS point Tokens, but losing to someone with lower RPS tokens will cause you to lose some RPS tokens depending on the gap you have with that person, this also gives the winner extra RPS tokens including the 10 RPS tokens, this RPS token is a simple ERC20 tokens, but it determines who seat on top of the leaderboard, this is where The Graph protocol comes in.&lt;/p&gt;

&lt;p&gt;I wanted the game to be multichain so users could transfer polygon proofs from one chain to another for this, I intended to use the wormhole protocol to communicate between polygon zkevm and scroll zkevm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why wormhole?
&lt;/h3&gt;

&lt;p&gt;Well they were offering some cool cash prizes, I have worked with blockchain interoperability before using Hyperlane so the concept wasn't new to me.&lt;/p&gt;

&lt;h3&gt;
  
  
  What other chain do I want to deploy the project on?
&lt;/h3&gt;

&lt;p&gt;Scroll zkevm, I learnt about Scroll from the event and they had a lot of cool cash prizes, 20k USDC in total, just deploy on their zkevm no edit needed, definitely winning a prize on Scroll was way easier than Polygon, because they were new and they had more prize category.&lt;/p&gt;

&lt;h3&gt;
  
  
  What other polygon service did I plan to use?
&lt;/h3&gt;

&lt;p&gt;I wanted to build with polygon ID, Remember I said users are rewarded with RPS tokens when they win a fight with a real human being? This was what polygon ID would be used for, Every user verifies themselves and their wallet, this verification would be in such a way that the user won't be able to use another address to challenge themselves.&lt;br&gt;
This is so important in order to prevent users from getting unfair advantages and also protect our achievement NFTs from fake fights, polygon ID would also verify age to make sure people below 18 can't stake assets.&lt;br&gt;
Talking about achievement NFTs, players earn NFTs for every milestone of unique victories they reach, from the first NFTs that require just one unique victory, to the one that requires 390625 unique victories to win, that is you have to defeat that many people. Easy right? 😄&lt;/p&gt;

&lt;h3&gt;
  
  
  How the Game would work
&lt;/h3&gt;

&lt;p&gt;So basically the game is a two-player two-round game, like Mortal Kombat, but with rock, paper, and scissors, players battle for RPS point tokens, they can also choose to stake NFTs, ERC20 tokens, and ether, stakes don't have to be equal. With every milestone of unique persons you defeat, you get rare achievement NFTs, (You get your first NFT Battle Ready, when you defeat your first opponent and RPS King NFT when you defeat your 390625th opponent). &lt;br&gt;
RPS point token reward system, winning a match gives you 10 RPS point tokens, Players with more RPST, lose RPST when they lose to people with less RPST, RPST determines who sits on top of the leaderboard. &lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
A has 1000 RPST, B has 10 RPST, and A loses the battles so B gets (1000 - 10) / 100 RPS tokens as a reward for winning someone on top and A loses (1000 - 10) / 50 RPST tokens for losing to someone below&lt;/p&gt;

&lt;p&gt;So the easiest way to earn RPST is to fight people on top of the leaderboard, this will incentivize the underdogs to stake more valuable items in and the people on top of the leaderboards could get more value per game on the risk of losing points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges faced
&lt;/h2&gt;

&lt;p&gt;My first challenge had to do with my personal life for the first week of the hackathon, I got extremely busy with work so I could only dedicate a little time to the Hackathon project, the next week I was free, only to come to the realization that Eth-online isn't really 3 weeks, it's for like 16days the whole event plus judging is for 21days? That was tough considering the fact that I intended to integrate a lot of features, Nevertheless, I pressed on.&lt;/p&gt;

&lt;p&gt;So I checked Wormhole and they didn't support neither polygon zkevm, nor Scroll, I ain't going down without a fight so I checked Hyperlane, and they don't support zkevm either 😞 so I had to drop this feature, it seemed like the best thing to do.&lt;/p&gt;

&lt;p&gt;So I went all in on Polygon ID, researching online and studying the documentation, I even downloaded the app from Play Store, but I couldn't really use it with my App the information around it was a bit confusing, maybe because I was under pressure, I couldn't find the right guide to simplify the whole thing for me within a short time period, let alone creating anti-spam proof, the whole information I got make it seemed that it will be difficult to create Anti-spam proof with Polygon ID, I will be glad to be wrong about this, so I dropped this feature to focus on the main game and the Graph Protocol.&lt;/p&gt;

&lt;p&gt;About three days before the submission deadline I was finally ready to deploy my smart contract on polygon zkevm, I had tested on the Hardhat local node and everything was fine, so what could go wrong?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw241tbtn1kf0lysd9u5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw241tbtn1kf0lysd9u5.gif" alt="Explosion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything went wrong for starters, I couldn't deploy the contract on zkevm, and I was getting some weird errors, stressed about what could be the error? debugging for almost a day, then I found the bug. I was deploying multiple contracts on the constructor, so basically my constructors were contract factories, to fix this I had to deploy the contracts separately and pass the contract address as arguments to the constructors, I don't know why it behaved like this, it worked fine on my local hardhat network and Polygon Mumbai, so I guessed the zkevm is not 100% compatible with the EVM.&lt;/p&gt;

&lt;p&gt;After fixing this bug I faced another challenge with my nextjs app, I could write to the blockchain on polygon zkevm, but I couldn't read from it, the same thing with scroll zkvm after, spending hours on this with no results, I found the error, this was it, I was using &lt;code&gt;wagmi&lt;/code&gt; to interact with the blockchain, but my error was that I didn't specify the chainId on my read requests hooks, so by default, I was reading the data from a different blockchain network, where the smart contract doesn't exist.&lt;br&gt;
Here is a similar issue on StackOverflow, I provided my solution to this question &lt;a href="https://stackoverflow.com/questions/76763812/wagmi-throws-error-contractfunctionexecutionerror-the-contract-function-owner/77280917#77280917" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/76763812/wagmi-throws-error-contractfunctionexecutionerror-the-contract-function-owner/77280917#77280917&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Time to deploy on a live server 😀 .
&lt;/h3&gt;

&lt;p&gt;I always host my React and Nextjs projects on Netlify so this wasn't any different, deployed to Netlify, and I wanted to play the game, but 💣 I was facing some weird issues. &lt;br&gt;
The app worked fine but anytime I tried to visit certain pages directly using the address bar I got the weird Nextjs, at first I thought it was caused by the Hydration error, I ignored that page but it didn't work even after fixing it so, I went online.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpuycvqmpu444bo2xvh24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpuycvqmpu444bo2xvh24.png" alt="The Nextjs Netlify error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The error message is shown above, so I came across this forum, and it was helpful, &lt;a href="https://answers.netlify.com/t/runtime-importmoduleerror-error-cannot-find-module-styled-jsx-nextjs-nextauth/95281" rel="noopener noreferrer"&gt;https://answers.netlify.com/t/runtime-importmoduleerror-error-cannot-find-module-styled-jsx-nextjs-nextauth/95281&lt;/a&gt;&lt;br&gt;
he fixed the issue by downgrading &lt;code&gt;@netlify/plugin-nextjs&lt;/code&gt;,  but this didn't solve my problem, so I had to downgrade my Nextjs version from &lt;code&gt;13.5.4&lt;/code&gt; to &lt;code&gt;13.4.6&lt;/code&gt;, which fixed the error for me.&lt;/p&gt;

&lt;p&gt;I fixed the Nextjs issue on the last day of the Hackathon, feeling happy and fulfilled about the many challenges I fixed in 3 days I was wondering what could stop me, my game was running smoothly on polygon zkevm, and I finally won 😁 . &lt;br&gt;
Have I? Not quite everything was working fine on polygon zkevm, but not on scroll zkevm, the contract read hook wasn't polling data from the scroll blockchain, and I had to refresh the page to poll data 😠 after some back and forth I checked my network console and found out the scroll websockets public rpc URL has been moved? to where I don't know, well I solved this by creating a scroll endpoint on &lt;a href="https://www.quicknode.com?tap_a=67226-09396e&amp;amp;tap_s=4253880-393f02&amp;amp;utm_source=affiliate&amp;amp;utm_campaign=generic&amp;amp;utm_content=affiliate_landing_page&amp;amp;utm_medium=generic" rel="noopener noreferrer"&gt;Quick-node&lt;/a&gt; and using custom providers instead of public providers from Wagmi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Have a better understanding of the protocols you plan on using for a hackathon beforehand.&lt;/li&gt;
&lt;li&gt;Ethonline isn't a 3 weeks hackathon so don't plan with 3 weeks in mind.&lt;/li&gt;
&lt;li&gt;Get your demo video quickly and on time, when I made my demo video my app wasn't working on any of the zkevm, so I demoed the app on the hardhat local network, while I continued battling my bugs.&lt;/li&gt;
&lt;li&gt;Don't be quick to use the latest version of any software, unknown bugs might be waiting for you (my Netlify and Nextjs issue).&lt;/li&gt;
&lt;li&gt;Test the app on the intended blockchain from time to time, the local blockchain might not be enough. &lt;/li&gt;
&lt;li&gt;Never rely on public providers, use RPCs they are more reliable, use &lt;a href="https://www.quicknode.com?tap_a=67226-09396e&amp;amp;tap_s=4253880-393f02&amp;amp;utm_source=affiliate&amp;amp;utm_campaign=generic&amp;amp;utm_content=affiliate_landing_page&amp;amp;utm_medium=generic" rel="noopener noreferrer"&gt;Quick-node&lt;/a&gt; they offer support for a lot of Blockchain and you can get started for free.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F856abd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F856abd.jpg" title="made at imgflip.com"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;While my Ethonline Hackathon didn't go as planned, I couldn't build what I planned to build, but I did manage to build a working product, you can check it out &lt;a href="https://ethglobal.com/showcase/rps-onchain-bp55v" rel="noopener noreferrer"&gt;https://ethglobal.com/showcase/rps-onchain-bp55v&lt;/a&gt; and as a consolation, my project won the pool prize on Scroll which was about 17.17 USDC, more importantly, I had fun and learned new things, I used the graph protocol for the first time and I enjoyed it, one product that fascinates me about this hackathon was polygon ID and I planned to use this product on my next Hackathon Chainlink Constellation. I will surely share my experience here and hopefully, I get better results, A la prochaine. &lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>ethonline</category>
      <category>polygon</category>
      <category>web3</category>
    </item>
    <item>
      <title>Smart Contract Upgrade</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Sat, 18 Mar 2023 08:54:03 +0000</pubDate>
      <link>https://dev.to/joshuajee/smart-contract-upgrade-1ec2</link>
      <guid>https://dev.to/joshuajee/smart-contract-upgrade-1ec2</guid>
      <description>&lt;p&gt;Smart contracts are self-executing programs that run on the Ethereum Virtual Machine (EVM). These programs are immutable by design, which means no update to the business logic after deployment. While this is good for user trust, decentralization, and security of smart contracts, it may be a drawback as vulnerabilities in smart contracts cannot be fixed after deployment.&lt;/p&gt;

&lt;p&gt;Smart Contracts are upgraded for various reasons, which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixing Bugs&lt;/li&gt;
&lt;li&gt;Fixing Security issues&lt;/li&gt;
&lt;li&gt;Adding new features to the Smart Contract&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a Smart contract upgrade?
&lt;/h2&gt;

&lt;p&gt;A smart contract upgrade is a process of updating the business logic of an already deployed smart contract while preserving the states (data) of the smart contract.&lt;br&gt;
There are different ways of upgrading smart contracts, and we will talk about a few of them in this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contract Migration&lt;/li&gt;
&lt;li&gt;Data separation&lt;/li&gt;
&lt;li&gt;Proxy Pattern&lt;/li&gt;
&lt;li&gt;Diamond Pattern (EIP-2535)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contract Migration
&lt;/h2&gt;

&lt;p&gt;This is one of the oldest and crudest way of upgrading smart contracts, it is very tedious and expensive in terms of gas fees and may be impractical in large applications. It is implemented by deploying a new smart contract with the updated business logic, and then copying the states from the old smart contract to the new one, then changing the smart contract address to the new one in your DApp.&lt;br&gt;
This method is used when the smart contract was developed without the intention to upgrade it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data separation
&lt;/h2&gt;

&lt;p&gt;This method uses two smart contracts; one smart contract contains the business logic, and the other smart contract contains the contract's data, users interact directly with the logic contract, and the logic contract calls the data contract as the name implies all state variables are stored here.&lt;/p&gt;

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

&lt;p&gt;Upgrades are done by changing ownership of the data contract to that of the new business logic contract and using the address of the new business contract in your DApp. This method is better than Contract Migration as it is cheaper, but you have to change the contract address with each upgrade you make which is not ideal as other software may depend on your Smart contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy Pattern
&lt;/h2&gt;

&lt;p&gt;This method makes use of an immutable proxy contract that stores the data and an upgradable logic contract, the user interacts directly with the immutable proxy contract, and this contract delegate calls the logic contract.&lt;/p&gt;

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

&lt;p&gt;To upgrade in this pattern, you need to deploy a new logic contract, then update the address on the proxy contract to that of the new one, subsequent calls to the proxy contract will be implemented by the new logic contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diamond Pattern (EIP-2535)
&lt;/h2&gt;

&lt;p&gt;This method is an extension of the Proxy Pattern. This pattern uses a contract called the Diamond. The Diamond contract delegate call multiple logic contracts called facets. These facets execute the logic, and the diamond contract stores the state (data). The most important feature of the Diamond pattern is that it is not constrained by the 24kb maximum contract size in solidity, as larger contracts can be splited into smaller facets, also with this pattern you don't need to update the whole contract during upgrades, you only need to deal with the facet that contains that function or add a new facet.&lt;/p&gt;

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

&lt;p&gt;In the Diamond pattern, upgrades are handled by a facet called the DiamondCutFacet with this facet, you can add, remove or replace functionalities. If this facet is removed the contract can't be upgraded anymore.&lt;/p&gt;

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

&lt;p&gt;In this article we have talked about four popular methods of upgrading smart contracts, the Contract Migration pattern should only be used when you deployed the contract without intention of upgrading it, it is not advisable to use Separation of Logic method as it brings the inconvience of changing the contract address with each deployment the Proxy Pattern is currently the most used pattern so more people in the EVM community understands it, but the Diamond pattern is a game changer, it makes it possible for developers to exceed the 24kb size limit of smart contracts, so you smart contract can grow to any size.&lt;/p&gt;

</description>
      <category>career</category>
      <category>eventsinyourcity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to Accept Crypto Payments in a Next.js Application using Coinbase Commerce</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Tue, 20 Sep 2022 09:59:43 +0000</pubDate>
      <link>https://dev.to/joshuajee/how-to-accept-crypto-payments-in-a-nextjs-application-using-coinbase-commerce-303e</link>
      <guid>https://dev.to/joshuajee/how-to-accept-crypto-payments-in-a-nextjs-application-using-coinbase-commerce-303e</guid>
      <description>&lt;p&gt;The adaptation of cryptocurrencies is increasing fast these digital assets can be used to settle debts, and several businesses now accept cryptocurrencies as a means of payment. The most significant advantage of cryptocurrencies is that they are decentralized, making payments easy as people can instantly transfer digital assets anywhere in the world without restrictions.&lt;/p&gt;

&lt;p&gt;Given that cryptocurrencies are gaining popularity, you may want to accept cryptocurrencies in your web application, one way to do that is by using coinbase commerce. Coinbase commerce is a platform that allows merchants to accept digital payments through cryptocurrencies, and they support many cryptocurrencies, you can look at their list of supported cryptocurrencies here.&lt;/p&gt;

&lt;p&gt;Next.js is a popular Frontend framework built on React.js, it supports serverless functions this will be very vital in this article, these serverless functions allow us to write backend codes which essentially eliminate the need to have two separate codebases for the frontend and backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;You need the following to successfully follow this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://commerce.coinbase.com/" rel="noopener noreferrer"&gt;Coinbase Commerce account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;Nodejs installed on your computer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ngrok.com/download" rel="noopener noreferrer"&gt;Ngrok installed on your computer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Basic Knowledge of Next.js or React&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Set up
&lt;/h2&gt;

&lt;p&gt;First, let’s create a new Next.js application by running the command below on the terminal, Follow the instructions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx create-next-app@latest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, navigate to the project directory and install the following dependencies by running the command below. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install &lt;/span&gt;coinbase-commerce-node axios


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;axios&lt;/code&gt; is an HTTP client and &lt;code&gt;coinbase-commerce-node&lt;/code&gt; is the coin base SDK for Nodejs.&lt;/p&gt;

&lt;p&gt;Once these packages have been installed, open the project directory with your text editor, and run the following command in your terminal to start the app in development mode.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The application will be served at &lt;code&gt;[localhost:3000](http://localhost:3000)&lt;/code&gt; if port 3000 is free, else another port will be chosen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Application
&lt;/h2&gt;

&lt;p&gt;In this article, we will be building a simple web-based e-commerce shop that accepts cryptocurrencies using Next.js, we will use coinbase commerce to create payment links, and we will create a webhook URL to verify transactions, and test this webhook locally using a tool called &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;Ngrok&lt;/a&gt;, the data source for the application will be a hard-coded array of shop items,  now open the project directory in your text editor, and let’s write some codes.&lt;/p&gt;

&lt;p&gt;You can get the source code of this project &lt;a href="https://github.com/Joshuajee/nextjs-crypto" rel="noopener noreferrer"&gt;here&lt;/a&gt;, feel free to clone the repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  The data source
&lt;/h3&gt;

&lt;p&gt;In a real-world application, the data would likely come from a database or a server, but in this article, it will be hard-coded. At the root directory of your project create a file name data.js this is where all the application data will come from, copy and paste the code snippet below in that file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Small Black Chair&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Soft Chair, Best value for Money&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spoon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spoon gets the best value for Money&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Small Table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Soft Table, Best value for Money&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Silver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ETH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Silver spoon set&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Silver Cup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.03&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BTC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cup for the big men&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Basic Cup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DOGE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Best value for Money&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Building the Home Page
&lt;/h3&gt;

&lt;p&gt;Next.js uses file-based routing so any react component exported as default in the &lt;code&gt;pages&lt;/code&gt; directory will be rendered as the page when that route is visited, you can learn more about it &lt;a href="https://nextjs.org/docs/routing/introduction" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;pages/index.js&lt;/code&gt; delete the boilerplate code and input the following code snippets, we will discourse the code next.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Products&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coinbase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/init&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hosted_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Price: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;coinbase&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Pay With Crtpto &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code snippet above contains two components, &lt;code&gt;Home&lt;/code&gt; and &lt;code&gt;Products&lt;/code&gt;, the &lt;code&gt;Home&lt;/code&gt; component is exported as the default component, while the &lt;code&gt;Product&lt;/code&gt; component is not exported this is because we are only using it in this file to display each product. &lt;/p&gt;

&lt;p&gt;The code snippet below in the &lt;code&gt;Home&lt;/code&gt; component maps the &lt;code&gt;products&lt;/code&gt; array to the &lt;code&gt;Product&lt;/code&gt; component.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Products&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;      


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s go into the &lt;code&gt;Product&lt;/code&gt; component, this component displays a particular product, and it contains a very important function, the &lt;code&gt;coinbase&lt;/code&gt; function, this function sends a post request to this route &lt;code&gt;/api/init&lt;/code&gt;, we will set up this route later if this request is successful this route will create a payment charge using the product &lt;code&gt;id&lt;/code&gt; and returns the charge details, then the code will open a new tab on the browser using the payment link returned from coinbase commerce.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the &lt;code&gt;coinbase&lt;/code&gt;  function below;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coinbase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/init&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hosted_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This piece of code &lt;code&gt;const data = await axios.post('/api/init', { id: product.id })&lt;/code&gt; send a post request to our api routes passing the product ID as the body of the request, and this line of code &lt;code&gt;window.open(data.data.hosted_url, '_blank');&lt;/code&gt; opens another tab in the browser, using the link returned from our post request, next we are going to set up the &lt;code&gt;init&lt;/code&gt; route.&lt;/p&gt;

&lt;h3&gt;
  
  
  Styling the Application
&lt;/h3&gt;

&lt;p&gt;Now let’s add some styling to give the application a better look, we are going to be using global CSS for this one, global CSS now open the styles/global.css file, delete the boilerplate CSS and paste the CSS code snippet below, you can learn more about global CSS in Next.js from &lt;a href="https://nextjs.org/docs/basic-features/built-in-css-support" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;whitesmoke&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-evenly&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.8em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Building the payment route handler
&lt;/h3&gt;

&lt;p&gt;Next.js allows us to create serverless functions so that we can create backend API route handlers. You can learn more about them &lt;a href="https://nextjs.org/docs/api-routes/introduction" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Next, create a file &lt;code&gt;pages/api/init.js&lt;/code&gt; and paste the following code snippets. we will discourse the code next.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coinbase-commerce-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COINBASE_API&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Charge&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coinInitRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chargeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pricing_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed_price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;local_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chargeData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;coinInitRoute&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We start by importing the modules needed to create a charge, we will be using &lt;code&gt;Client&lt;/code&gt; and &lt;code&gt;resources&lt;/code&gt; from the &lt;code&gt;coinbase-commerce-node&lt;/code&gt; package, next we import our product data,&lt;/p&gt;

&lt;p&gt;this line of code &lt;code&gt;Client.init(process.env.COINBASE_API)&lt;/code&gt; initiates the coinbase commerce client using our coinbase commerce API key we will talk about how to get this later.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coinbase-commerce-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COINBASE_API&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Charge&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The flow of this route handler is simple, we retrieve the product id from the &lt;code&gt;req.body&lt;/code&gt; and use it to search for the correct product. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we create a charge using the product data, we set the &lt;code&gt;pricing_type&lt;/code&gt; to &lt;code&gt;fixed_price&lt;/code&gt; so the user can’t pay any amount, the pricing type can be set to &lt;code&gt;no_price&lt;/code&gt; this will allow the user to pay any amount, &lt;code&gt;metadata&lt;/code&gt; field is used to send additional data to coinbase commerce for identifying the user, this &lt;code&gt;metadata&lt;/code&gt; is useful in identifying the user and the product they paid for, in our use case we set the &lt;code&gt;userID&lt;/code&gt; to 1.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chargeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;pricing_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed_price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;local_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next two lines of codes create a charge by sending a request to coinbase commerce once this request is successful it sends the charged object to the client&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chargeData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can check the coinbase commerce documentation &lt;a href="https://docs.cloud.coinbase.com/commerce/docs/webhooks-events" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Coinbase API key
&lt;/h3&gt;

&lt;p&gt;We have created our application, but we can’t create charges just yet because we need an API KEY from coinbase commerce to get started, first create a &lt;code&gt;.env&lt;/code&gt; file at the root of the project, and add &lt;code&gt;COINBASE_API&lt;/code&gt; and &lt;code&gt;COINBASE_SECRET&lt;/code&gt; to the &lt;code&gt;.env&lt;/code&gt; file, the file should look like the one below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

COINBASE_API &lt;span class="o"&gt;=&lt;/span&gt; 
COINBASE_SECRET &lt;span class="o"&gt;=&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Currently, coinbase commerce doesn’t have a sandbox or a testing environment, so we will have to allow our testing with live API keys and real cryptocurrencies. So log in to your coinbase commerce &lt;a href="https://commerce.coinbase.com/" rel="noopener noreferrer"&gt;account&lt;/a&gt;, click on the profile icon on the top right corner of the page, then click on settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4756lxehppfziib03anf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4756lxehppfziib03anf.png" alt="Create API Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the Security tab and click on the &lt;code&gt;New API key&lt;/code&gt; button to create an API key, then copy the API key, open the &lt;code&gt;.env&lt;/code&gt; file and paste the keys to the &lt;code&gt;COINBASE_API&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xvr4q7o957c929k0bxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xvr4q7o957c929k0bxp.png" alt="Coinbase Api"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Running the Application
&lt;/h3&gt;

&lt;p&gt;Run the application with this command &lt;code&gt;npm run dev&lt;/code&gt; on the terminal then view the app on your browser and click on &lt;code&gt;Pay With Crypto&lt;/code&gt; button on any of the items, this will open a new tab to make payments.&lt;/p&gt;

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

&lt;p&gt;You will have just one hour to make a payment, by choosing any of the methods below, you can choose to pay with coinbase or any of the cryptocurrencies listed below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oxx1krxjq3z0zkkyhi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8oxx1krxjq3z0zkkyhi4.png" alt="Coinbase Pay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying Transactions
&lt;/h2&gt;

&lt;p&gt;Now users can buy items from your application using cryptocurrencies but can’t verify who made the transaction or what they bought. To verify transactions you need to set up a webhook URL for coinbase commerce to send an HTTP post request to that route when a user makes a payment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the webhook route
&lt;/h3&gt;

&lt;p&gt;Next, create a file &lt;code&gt;pages/api/verify.js&lt;/code&gt; and paste the following code snippets, we will discourse the code next.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

import &lt;span class="o"&gt;{&lt;/span&gt; Client, Webhook &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'coinbase-commerce-node'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

Client.init&lt;span class="o"&gt;(&lt;/span&gt;process.env.COINBASE_API&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;default async &lt;span class="k"&gt;function &lt;/span&gt;coinVerifyRoute&lt;span class="o"&gt;(&lt;/span&gt;req, res&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    try &lt;span class="o"&gt;{&lt;/span&gt;

        const rawBody &lt;span class="o"&gt;=&lt;/span&gt; JSON.stringify&lt;span class="o"&gt;(&lt;/span&gt;req.body&lt;span class="o"&gt;)&lt;/span&gt;
        const signature &lt;span class="o"&gt;=&lt;/span&gt; String&lt;span class="o"&gt;(&lt;/span&gt;req.headers[&lt;span class="s1"&gt;'x-cc-webhook-signature'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        const webhookSecret &lt;span class="o"&gt;=&lt;/span&gt; String&lt;span class="o"&gt;(&lt;/span&gt;process.env.COINBASE_SECRET&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        const event &lt;span class="o"&gt;=&lt;/span&gt; Webhook.verifyEventBody&lt;span class="o"&gt;(&lt;/span&gt;rawBody, signature, webhookSecret&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        console.log&lt;span class="o"&gt;(&lt;/span&gt;event&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;event.type &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'charge:pending'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            // TODO
            // user paid, but transaction not confirm on blockchain 
            console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;event.type &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'charge:confirmed'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            // TODO
            // all good, charge confirmed
            console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"confirmed"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;event.type &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'charge:failed'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            // TODO
            // charge failed or expired
            console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"failed"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt; catch &lt;span class="o"&gt;(&lt;/span&gt;e&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        res.status&lt;span class="o"&gt;(&lt;/span&gt;500&lt;span class="o"&gt;)&lt;/span&gt;.send&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="o"&gt;}&lt;/span&gt;

    res.send&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;success&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We start by importing the modules needed to make our webhook work, we will be using &lt;code&gt;Client&lt;/code&gt; and &lt;code&gt;Webhook&lt;/code&gt; from the &lt;code&gt;coinbase-commerce-node&lt;/code&gt; package.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Webhook&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coinbase-commerce-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we verify that the post request is coming from coinbase commerce and not a malicious person, you can notice that we are using an environment variable &lt;code&gt;COINBASE_SECRET&lt;/code&gt; this variable will be gotten later from coinbase commerce when we try to test our webhook. This piece of code &lt;code&gt;Webhook.verifyEventBody(rawBody, signature, webhookSecret);&lt;/code&gt; verifies the message sender, if the message is not coming from coinbase commerce it throws an error.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-cc-webhook-signature&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webhookSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COINBASE_SECRET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Webhook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifyEventBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webhookSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next let’s talk about events that can be sent by coinbase commerce, in our code we had just three events, which are &lt;code&gt;charge:pending&lt;/code&gt;, &lt;code&gt;'charge:confirmed&lt;/code&gt;, and &lt;code&gt;'charge:failed&lt;/code&gt;, the &lt;code&gt;charge:pending&lt;/code&gt; event is fired when the user have made payment but the transaction has not been confirmed on the blockchain, the &lt;code&gt;'charge:confirmed&lt;/code&gt; as the name implies is sent when the transaction has been confirmed on the blockchain, you should confirm the price before you give value and &lt;code&gt;'charge:failed'&lt;/code&gt; when the transaction failed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;charge:pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// TODO&lt;/span&gt;
            &lt;span class="c1"&gt;// user paid, but transaction not confirm on blockchain &lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;charge:confirmed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// TODO&lt;/span&gt;
            &lt;span class="c1"&gt;// all good, charge confirmed&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;charge:failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// TODO&lt;/span&gt;
            &lt;span class="c1"&gt;// charge failed or expired&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before you give value to your customer, first confirm the amount paid and the currency, and use the information on the &lt;code&gt;metadata&lt;/code&gt; field, to identify customer and products, you can learn more about the coinbase commerce webhooks &lt;a href="https://docs.cloud.coinbase.com/commerce/docs/webhooks-events" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the webhook Url
&lt;/h3&gt;

&lt;p&gt;To test our webhook URL we will make use of a tool called Ngrok, if you don’t have it you can install it &lt;a href="https://ngrok.com/download" rel="noopener noreferrer"&gt;here&lt;/a&gt;, once installed run the following commands&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above command will run our app on port 3000, next run the command below to connect your application to the internet using ngrok, make sure your application port is the same as the one on the command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ngrok HTTP 3000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Copy the second Forwarding URL we are going to use this as our domain for the coinbase commerce URL&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting the webhook Url
&lt;/h3&gt;

&lt;p&gt;Login to your coinbase commerce account, navigate settings, and click on the notification tab, then click on the &lt;code&gt;Add Endpoint&lt;/code&gt; past the Forwarding URL gotten from ngrok, and add the &lt;code&gt;/api/verify&lt;/code&gt; route as shown in the image below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note on a live server this webhook URL should be &lt;a href="https://your-domain/api/verify" rel="noopener noreferrer"&gt;https://your-domain/api/verify&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rqngcq4pb9boopbx2yg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rqngcq4pb9boopbx2yg.png" alt="Webhook Url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next get your shared secret by clicking the &lt;code&gt;Show shared secret&lt;/code&gt; button on the bottom right corner, copy the shared secret, open the &lt;code&gt;.env&lt;/code&gt; file and assign it to the &lt;code&gt;COINBASE_SECRET&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4ri5b2m71cpbu5m8b66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4ri5b2m71cpbu5m8b66.png" alt="Shared Secret"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s manually test our webhook by sending it fake requests, First, click on the edit button on the right of the webhook endpoint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fruf3q4dggrkblwk5ec9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fruf3q4dggrkblwk5ec9k.png" alt="Click Edit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;code&gt;Send Test&lt;/code&gt; button and choose any event of you choice, let’s start we confirm as shown in the photo below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0ym10ud2gr1r8cv02iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0ym10ud2gr1r8cv02iw.png" alt="Send Test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should get a response like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yk01klprgq57wsrxj2v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yk01klprgq57wsrxj2v.png" alt="Test Response"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look at your terminal, to see the dummy data sent by coinbase commerce, feel free to test as many events as you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas6vjij9t31ifdarlzjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas6vjij9t31ifdarlzjo.png" alt="Webhook Response"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this article, we built a simple web-based ecommerce shop that accepts cryptocurrencies using Next.js, we talked about &lt;code&gt;coinbase-commerce-node&lt;/code&gt;, which is the official nodejs SDK for coinbase commerce, we created API keys in coinbase commerce, and retrieved our coinbase commerce “shared secret”, we created a payment link with coinbase-commerce using this SDK, we created a webhook URL to verify transactions, and we manually tested our webhook endpoint locally from our coinbase commerce account, using a tool named ngrok, you can get the source code of this project &lt;a href="https://github.com/Joshuajee/nextjs-crypto" rel="noopener noreferrer"&gt;here&lt;/a&gt;, feel free to clone the repo.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>web3</category>
      <category>node</category>
    </item>
    <item>
      <title>How to fix defaultValue error while working with textarea in React</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Fri, 04 Feb 2022 01:15:30 +0000</pubDate>
      <link>https://dev.to/joshuajee/how-to-fix-defaultvalue-error-while-working-with-textarea-in-react-1a55</link>
      <guid>https://dev.to/joshuajee/how-to-fix-defaultvalue-error-while-working-with-textarea-in-react-1a55</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In HTML, if you want a textbox with some initial text you wrap text inside the textarea tag like this &lt;code&gt;&amp;lt;textarea&amp;gt; Hello World &amp;lt;/textarea&amp;gt;&lt;/code&gt;, this is fully editable, but if you try this in react you will get an error. Trying to use the &lt;code&gt;defaultValue&lt;/code&gt; prop in react won't work either. if you add a value prop to the textarea the value of the text will be displayed but then it won't be editable, this is because the &lt;code&gt;value&lt;/code&gt; prop is immutable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Passing a &lt;code&gt;value&lt;/code&gt; prop to textarea like this &lt;code&gt;&amp;lt;textarea value={'Hello World'}&amp;gt; &amp;lt;/textarea&amp;gt;&lt;/code&gt;, will display the text Hello World on the textbox, but it won't be editable to make it editable we need to pass the a state to the &lt;code&gt;value&lt;/code&gt; prop and update that state with the &lt;code&gt;onChange&lt;/code&gt; prop like the code below.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;TextBox&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;textarea&lt;/span&gt; 
             &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
             &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/textarea&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;TextBox&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the TextBox component, I initialize the &lt;code&gt;text&lt;/code&gt; state with 'Hello World' and passed it to the textarea as a value prop, this will be the initial text displayed in the text area. &lt;code&gt;onChange={(e) =&amp;gt; setText(e.target.value) }&lt;/code&gt; this line of code updates the &lt;code&gt;text&lt;/code&gt; state, with the new value.&lt;/p&gt;

&lt;p&gt;You can learn more about handling form in react &lt;a href="https://reactjs.org/docs/forms.html#controlled-components"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>MongoDB Submission Post Trader Chart</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Thu, 13 Jan 2022 15:33:49 +0000</pubDate>
      <link>https://dev.to/joshuajee/mongodb-submission-post-trader-chart-18nb</link>
      <guid>https://dev.to/joshuajee/mongodb-submission-post-trader-chart-18nb</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;This is a charting software for doing technical analysis on the Forex, Crypto and Stock market etc. It comes with Trend indicators like the Moving Average, Bollinger Band, Ichimoku Kinkō Hyō. It also comes with oscillators like the Relative strength index, Moving Average Convergence Divergence and Average True Range.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Prime Time: Stock Analysis&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Joshuajee"&gt;
        Joshuajee
      &lt;/a&gt; / &lt;a href="https://github.com/Joshuajee/Trader-Chart"&gt;
        Trader-Chart
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;br&gt;
&lt;div&gt;
  &lt;a href="https://github.com/Joshuajee/Trader-Chart/"&gt;
    &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d6lx0klI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/Joshuajee/Trader-Chartimages/logo.png" alt="Logo" width="80" height="80"&gt;
  &lt;/a&gt;
  &lt;h3&gt;
Trader Chart&lt;/h3&gt;
  &lt;p&gt;
    Web Based Charting software to analyze the Forex, Stocks and Crypto Market
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://trader-chart.herokuapp.com/" rel="nofollow"&gt;View App&lt;/a&gt;
    ·
    &lt;a href="https://github.com/Joshuajee/Trader-Chart/issues"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/Joshuajee/Trader-Chart/issues"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;

  Table of Contents
  &lt;ol&gt;
    &lt;li&gt;
      &lt;a href="https://github.com/Joshuajee/Trader-Chart#about-the-project"&gt;About The Project&lt;/a&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#built-with"&gt;Built With&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="https://github.com/Joshuajee/Trader-Chart#getting-started"&gt;Getting Started&lt;/a&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#prerequisites"&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#installation"&gt;Installation&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#preview"&gt;Preview&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#license"&gt;License&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://github.com/Joshuajee/Trader-Chart#contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;h2&gt;
About The Project&lt;/h2&gt;
&lt;p&gt;This is a charting software for doing technical analysis on the Forex, Crypto and Stock market etc. It comes with Trend indicators like the Moving Average, Bollinger Band, Ichimoku Kinkō Hyō. It also comes with oscillators like the Relative strength index, Moving Average Convergence Divergence and Average True Range.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Joshuajee/Trader-Chart./images/chart.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--goqLS6YJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/Joshuajee/Trader-Chart./images/chart.png" alt="Trader Chart Screen Shot" title="App screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://github.com/Joshuajee/Trader-Chart#top"&gt;back to top&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;
Built With&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/" rel="nofollow"&gt;React.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/" rel="nofollow"&gt;Mongodb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/" rel="nofollow"&gt;Nodejs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://expressjs.com/" rel="nofollow"&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://formidable.com/open-source/victory/" rel="nofollow"&gt;Victory Chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(&lt;a href="https://github.com/Joshuajee/Trader-Chart#top"&gt;back to top&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
Getting Started&lt;/h2&gt;
&lt;h3&gt;
Prerequisites&lt;/h3&gt;
&lt;p&gt;This is an example of how to list things you need to use the software and how to install them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nodejs&lt;/li&gt;
&lt;li&gt;npm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
Installation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create A time Series collection in Mongodb &lt;a href="https://docs.mongodb.com/manual/core/timeseries-collections/" rel="nofollow"&gt;Click Here&lt;/a&gt;
a time series collection can only be created…&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Joshuajee/Trader-Chart"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://trader-chart.herokuapp.com/"&gt;Click Here&lt;/a&gt; to view the app&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;All data stored in MongoDB Atlas &lt;code&gt;Timeseries&lt;/code&gt; collection for storing the data for each asset.&lt;/p&gt;

&lt;h4&gt;
  
  
  Built With
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/"&gt;React.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/"&gt;Mongodb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/"&gt;Nodejs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://formidable.com/open-source/victory/"&gt;Victory Chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  DEMO
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/w-agp1JobQU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trader-chart.herokuapp.com/"&gt;Click Here&lt;/a&gt; for Live Demo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FBtqOPo0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vepta02a3pc0urd9jckz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FBtqOPo0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vepta02a3pc0urd9jckz.png" alt="EURUSD CHART" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_7-n_Czj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46t5eac6kjj1yqd9tu7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_7-n_Czj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46t5eac6kjj1yqd9tu7s.png" alt="Indicator Modal" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0RHPImwu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yim6vvlxl2dmj14b9y0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0RHPImwu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yim6vvlxl2dmj14b9y0s.png" alt="Ichimoku Modal" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZOt7a1U_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0emn3t170jvvocwfxpsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZOt7a1U_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0emn3t170jvvocwfxpsv.png" alt="Color Picker" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_loRp6KG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mglknv8z59f28mutt7az.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_loRp6KG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mglknv8z59f28mutt7az.png" alt="IChimoku Cloud" width="880" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ADXn6A5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/158hkpcucrquwf0w07l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ADXn6A5X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/158hkpcucrquwf0w07l3.png" alt="Oscilators" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--llmsc1nT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5bcyv79jgj9tzvq5vjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--llmsc1nT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5bcyv79jgj9tzvq5vjd.png" alt="Bollinger Band and Average True Range" width="880" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>atlashackathon</category>
    </item>
    <item>
      <title>How to Integrate Typesense Search Engine in a Nodejs application</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Wed, 01 Dec 2021 22:48:37 +0000</pubDate>
      <link>https://dev.to/joshuajee/how-to-integrate-typesense-search-engine-in-a-nodejs-application-5654</link>
      <guid>https://dev.to/joshuajee/how-to-integrate-typesense-search-engine-in-a-nodejs-application-5654</guid>
      <description>&lt;p&gt;Tried building an application that requires efficient search? Maybe an online store or library catalog system?&lt;/p&gt;

&lt;p&gt;It is hard to build search engines that are typo tolerant, effective and efficient. A typographical error could make a search return nothing even though the requested item is on the database.&lt;br&gt;
Typesense could save you and your app users from such stress as you would not need to spend time building a search engine. And your users can effectively use the search feature in your application which would give them a great user experience.&lt;br&gt;
Typesense is an open-source typo-tolerant search engine for developers, developed to reduce the time to market for apps that require effective and efficient search.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;In this article, we will cover the following:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setting up Typesense Cloud&lt;/li&gt;
&lt;li&gt;Setting up our nodejs app&lt;/li&gt;
&lt;li&gt;Initializing the client&lt;/li&gt;
&lt;li&gt;Creating a Typesense Collection&lt;/li&gt;
&lt;li&gt;Setting up the express app&lt;/li&gt;
&lt;li&gt;Adding item to our collection&lt;/li&gt;
&lt;li&gt;Searching our collection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Setting up Typesense Cloud&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can use Typesense by either installing its docker image on your server or using the Typesense cloud hosting solution, which is the easiest way to get started with it, so we are using this option. Click &lt;a href="https://cloud.typesense.org/" rel="noopener noreferrer"&gt;Here&lt;/a&gt; to get started and sign in with Github.&lt;/p&gt;

&lt;p&gt;Once authenticated, follow these steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scroll down and launch a cluster wait for about 4 to 6 minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7e7qrxptw09g87h6fo7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7e7qrxptw09g87h6fo7h.png" alt="Creating A Cluster"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on Generate API Keys. It will download a text file containing credentials needed to authenticate our app with Typesense cloud.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu033tj1o7n1dvpm24j4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu033tj1o7n1dvpm24j4d.png" alt="Generate API Key "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Nodejs App
&lt;/h2&gt;

&lt;p&gt;Follow these steps, if you have Nodejs installed on your system if you don't download the latest version &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and follow the steps.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Install the following packages &lt;code&gt;express&lt;/code&gt;,  &lt;code&gt;typesense&lt;/code&gt; and &lt;code&gt;nodemon&lt;/code&gt; by running the following command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

npm i express typesense nodemon


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Add &lt;code&gt;"dev": "nodemon app.js"&lt;/code&gt; to the script part of the package.json file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nodemon app.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After these are done, setup the project structure to look like this.&lt;/p&gt;

&lt;p&gt;📦express-typesense-app&lt;/p&gt;

&lt;p&gt;┣ 📂Typesense&lt;/p&gt;

&lt;p&gt;┃ ┣ 📜bookCollection.js&lt;/p&gt;

&lt;p&gt;┃ ┗ 📜client.js&lt;/p&gt;

&lt;p&gt;┣ 📜app.js&lt;/p&gt;

&lt;p&gt;┣ 📜package.json&lt;/p&gt;

&lt;p&gt;┗ 📜package-lock.json&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Initializing the client&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Navigate to the &lt;code&gt;Typesense&lt;/code&gt; Folder, paste codes below in the &lt;code&gt;client.js&lt;/code&gt; file, The first line imports &lt;code&gt;Typesense&lt;/code&gt; into our code, then we create a &lt;code&gt;Typesense Client&lt;/code&gt; instance, this instance receives an object of configurations, needed to authenticate our app with Typesense, next we export this &lt;code&gt;client&lt;/code&gt; so it will be available for other files. Fill in the information gotten from the text file downloaded when you generated API keys, since we are running on the backend and we want to have write access use the Admin API Key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Typesense&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typesense&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Typesense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-typesense-node-gotten-from-type-sense-cloud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// For Typesense Cloud use xxx.a1.typesense.net&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;443&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// For Typesense Cloud use 443&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;   &lt;span class="c1"&gt;// For Typesense Cloud use https&lt;/span&gt;
  &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-typesense-admin-api-key-gotten-from-type-sense-cloud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;connectionTimeoutSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating a Typesense Collection
&lt;/h2&gt;

&lt;p&gt;Typesense, a collection is a group of related documents, by are like tables in relational a database. When we create a collection, we give it a name and describe the fields that will be indexed when a document is added to the collection.&lt;/p&gt;

&lt;p&gt;For each field, we define its &lt;code&gt;name, type&lt;/code&gt;, and whether it's a &lt;code&gt;facet&lt;/code&gt; field. A facet field allows us to cluster the search results into categories. &lt;/p&gt;

&lt;p&gt;We also define a &lt;code&gt;default_sorting_field&lt;/code&gt; that determines how the results must be sorted when no &lt;code&gt;sort_by&lt;/code&gt; clause is provided. In this case, books that have more ratings will be ranked higher.  This line of code &lt;code&gt;client.collections().create(booksSchema)&lt;/code&gt; create the book collection from the book schema. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This code will throw an error if the collection already exists, to prevent the app from this crashing handle the Error, by calling the error callback. as done in the code below &lt;code&gt;err =&amp;gt; {}&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;booksSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;books&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fields&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string[]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;facet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image_url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;publication_year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;int32&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;facet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings_count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;int32&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;average_rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;float&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default_sorting_field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings_count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;booksSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setting up the express server
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;app.js&lt;/code&gt; on the root directory of the application, we import the &lt;code&gt;express&lt;/code&gt; this is needed to create an express server, line 2 imports the Typesense &lt;code&gt;client&lt;/code&gt; this client will be used to make requests to Typesense, line 3 creates the book Collection if it doesn't exist.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Typesense/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Typesense/bookCollection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we create an express app, the next two lines of codes attach the middleware needed for the app to receive post data from post request.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Searching for books in our collection
&lt;/h3&gt;

&lt;p&gt;This route handles GET requests to &lt;code&gt;localhost:3000/search?q=&lt;/code&gt;, the first line of code in this route get the user search input from the &lt;code&gt;q&lt;/code&gt; query, the second line builds the search object &lt;code&gt;searchParameters&lt;/code&gt;, from the search object we see that we are querying our books by its &lt;code&gt;title&lt;/code&gt; and sorting by &lt;code&gt;ratings_count&lt;/code&gt; in descending order, &lt;code&gt;res.send(searchResults)&lt;/code&gt; sends the search results to the client.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;


&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchParameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;q&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;         &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query_by&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sort_by&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings_count:desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;books&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchParameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Adding data to book collection
&lt;/h3&gt;

&lt;p&gt;This route handles POST request to &lt;code&gt;localhost:3000/add-book&lt;/code&gt;,  the first line of code get the body of the post request, which in this case is the book we want to add to our collection &lt;code&gt;client.collections('books').documents().create(book)&lt;/code&gt; add the book to our collection. &lt;code&gt;res.send(data)&lt;/code&gt; sends the book data to the client.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;


&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/add-book&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;books&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This codeblock runs the server on port &lt;code&gt;3000&lt;/code&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&lt;code&gt;App running on port &amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;${&amp;lt;/span&amp;gt;&amp;lt;span class="nx"&amp;gt;port&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;span class="s2"&amp;gt;...&lt;/code&gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Adding Item to our Collection&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I will be using Postman to test this app, if you are new to Postman, click &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt; to download it, set up a workspace, and create a collection.&lt;/p&gt;

&lt;p&gt;I added 3 books to the book collection,  titled &lt;code&gt;How to use Typesense in a Nodejs application&lt;/code&gt;, &lt;code&gt;I want to Dance&lt;/code&gt;, &lt;code&gt;Best Dance Move&lt;/code&gt; with the following ratings respectively 4.55, 3.55, 4.35.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmnhbl2ksgzjsbb2052i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmnhbl2ksgzjsbb2052i.png" alt="Adding Books"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Searching for Item in our Collection
&lt;/h2&gt;

&lt;p&gt;Searching for a book titled &lt;strong&gt;&lt;em&gt;Best Dance Moves&lt;/em&gt;&lt;/strong&gt;, Noticed, I deliberately made errors in the spelling by searching &lt;strong&gt;&lt;em&gt;Bezt Dense Movee&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and Typesense returns Two books that contain the word Dance in its title.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0uuvmzfjbp64b1r7edn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0uuvmzfjbp64b1r7edn.png" alt="Searching For Book"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Searching for a "Harry Potter" which is not in our book collection returns zero items.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyg6o9fljd577dwebon9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyg6o9fljd577dwebon9m.png" alt="Harry Potter search"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this article, we talk about Typesense and how to get started with Typesense cloud, connecting to Typesense cloud, we created a typesense collection. We used the Typesense javascript library, this library works also works on Web Browsers, when used on Web Browser, use the search API key that doesn't grant write access. Typesense supports other languages click &lt;a href="https://typesense.org/docs/guide/building-a-search-application.html#sample-dataset" rel="noopener noreferrer"&gt;here&lt;/a&gt; to learn about them.&lt;/p&gt;

&lt;p&gt;Using Postman to test our application we saw that Typesense is very typo tolerant, easy to use, and fast.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>node</category>
    </item>
    <item>
      <title>Node.js GitHub Authentication using Passport.js and MongoDB</title>
      <dc:creator>Joshua Evuetapha</dc:creator>
      <pubDate>Mon, 08 Nov 2021 14:38:54 +0000</pubDate>
      <link>https://dev.to/joshuajee/nodejs-github-authentication-using-passportjs-and-mongodb-2lfd</link>
      <guid>https://dev.to/joshuajee/nodejs-github-authentication-using-passportjs-and-mongodb-2lfd</guid>
      <description>&lt;p&gt;In this article, you will learn how to authenticate with GitHub using Passport.js in a Nodejs express app. &lt;/p&gt;

&lt;p&gt;You can get the source code for this project &lt;a href="https://github.com/Joshuajee/passport-github-auth" rel="noopener noreferrer"&gt;here&lt;/a&gt;, this project can be used as a boilerplate code when setting up an express app that uses Passportjs for authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic Knowledge of NodeJS&lt;/li&gt;
&lt;li&gt;Node JS should be installed on your system.
## What is Passport.js?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Passport is authentication middleware for Node.js. It is very flexible and modular. A comprehensive set of strategies supports authentication using a username and password, Google, Facebook, Apple, Twitter, and more. Find out more about Passport &lt;a href="http://www.passportjs.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Github Application
&lt;/h2&gt;

&lt;p&gt;Before using passport-github2, you must have a Github account and register an application with Github. If you have not done this, You can do that &lt;a href="https://github.com/settings/applications/new" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Your Homepage URI and Callback URI should match the one in your application. Your application will be issued a Client ID and Client secret, which this strategy needs to work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_96D7FF9291F95727D81A56AA1A763CC4A64AC3AFC24A94BFB0A28786BA9BD4FB_1635810132201_git.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_96D7FF9291F95727D81A56AA1A763CC4A64AC3AFC24A94BFB0A28786BA9BD4FB_1635810132201_git.png" alt="Github Application setup page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up our Project
&lt;/h2&gt;

&lt;p&gt;To start, create a Nodejs project by running this command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Install the following packages by running these commands.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express express-session ejs mongoose passport passport-github2 dotenv nodemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the command is successful, you will see something like the image below, &lt;code&gt;node_modules&lt;/code&gt; folder will be created and &lt;code&gt;package-lock.json&lt;/code&gt; file will also be created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_96D7FF9291F95727D81A56AA1A763CC4A64AC3AFC24A94BFB0A28786BA9BD4FB_1635801691464_pack.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpaper-attachments.dropbox.com%2Fs_96D7FF9291F95727D81A56AA1A763CC4A64AC3AFC24A94BFB0A28786BA9BD4FB_1635801691464_pack.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is the project structure for this project.&lt;br&gt;
📦passportjs&lt;br&gt;
 ┣ 📂controller&lt;br&gt;
 ┃ ┣ 📜account.js&lt;br&gt;
 ┃ ┗ 📜auth.js&lt;br&gt;
 ┣ 📂model&lt;br&gt;
 ┃ ┗ 📜UserModel.js&lt;br&gt;
 ┣ 📂routes&lt;br&gt;
 ┃ ┣ 📜account.js&lt;br&gt;
 ┃ ┗ 📜auth.js&lt;br&gt;
 ┣ 📂utils&lt;br&gt;
 ┃ ┗ 📜github.js&lt;br&gt;
 ┣ 📂views&lt;br&gt;
 ┃ ┣ 📜account.ejs&lt;br&gt;
 ┃ ┗ 📜index.ejs&lt;br&gt;
 ┣ 📜.env&lt;br&gt;
 ┣ 📜.gitignore&lt;br&gt;
 ┣ 📜app.js&lt;br&gt;
 ┣ 📜package-lock.json&lt;br&gt;
 ┣ 📜package.json&lt;br&gt;
 ┣ 📜README.md&lt;br&gt;
 ┗ 📜server.js&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up our Express Server
&lt;/h2&gt;

&lt;p&gt;At this point, our application set. Now let’s go ahead and set up our express server. To get started, first create &lt;code&gt;server*.js&lt;/code&gt; file* in the project root directory. &lt;br&gt;
Next, import the mongoose for our database connection and &lt;code&gt;dotenv&lt;/code&gt; to lead our &lt;a href="https://www.twilio.com/blog/2017/08/working-with-environment-variables-in-node-js.html" rel="noopener noreferrer"&gt;environment variables&lt;/a&gt; with the code below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');
const dotenv = require('dotenv');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, create a &lt;code&gt;.env&lt;/code&gt; file in your project root directory, where we will store our environment variables later in this session. Then make the available in our application with the code below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotenv.config({ path: './.env' });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Import app.js into the code in this file export an express app, this app will be explained next in this article.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = require('./app');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we make a connection to the mongoose database with the code below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongoose
  .connect(process.env.DATABASE, { useUnifiedTopology: true })
  .then(() =&amp;gt; console.log('DB connection successful!'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we assign a port to the express application. The application will be listening to the port provided by the environment or port 8081 if there is no environment port.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const port = process.env.PORT || 8081;

app.listen(port, () =&amp;gt; {
  console.log(`App running on port ${port}...`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The following line of codes listens for the following events &lt;code&gt;uncaughtException&lt;/code&gt;, &lt;code&gt;unhandledRejection&lt;/code&gt;, and &lt;code&gt;SIGTERM&lt;/code&gt; respectively, and shut down the server once either one of them occurs.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process.on('uncaughtException', err =&amp;gt; {
    console.log('UNCAUGHT EXCEPTION! 💥 Shutting down...');
    console.log(err.name, err.message);
    process.exit(1);
});

process.on('unhandledRejection', err =&amp;gt; {
    console.log('UNHANDLED REJECTION! 💥 Shutting down...');
    console.log(err.name, err.message);
    server.close(() =&amp;gt; {
      process.exit(1);
    });
});

process.on('SIGTERM', () =&amp;gt; {
    console.log('👋 SIGTERM RECEIVED. Shutting down gracefully');
    server.close(() =&amp;gt; {
      console.log('💥 Process terminated!');
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Your &lt;code&gt;.env&lt;/code&gt; file should look like this. Put your credentials on the required fields. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE = your-mongo-db-uri
GITHUB_CLIENT_ID = your-github-app-client-id
GITHUB_CLIENT_SECRET = your-github-app-client-secret
GITHUB_CALLBACK_URL = your-github-app-callback-url
SESSION_SECRET = your-app-session-secret-it-can-be-any-string-of-your-choice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setting up our Express Application
&lt;/h2&gt;

&lt;p&gt;Now let’s go ahead and setup our express application. To get started, create an &lt;code&gt;app.js&lt;/code&gt; in the project root directory.  first we import &lt;code&gt;express&lt;/code&gt;, next we import &lt;code&gt;express-session&lt;/code&gt; this is a middleware for handling user sessions in express.&lt;br&gt;
Then import two route handlers on for handling authentication request and the other for handling request in user account. These route handlers will be explained next.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const session = require('express-session');
const authRouter = require('./routes/auth');
const accountRouter = require('./routes/account');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is where we create the express and by calling the express function which is a top level function exported by the express module and assign it to the &lt;code&gt;app&lt;/code&gt; variable.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = express();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we configure the directory where the template files will be located. The first line of code set the view directory to &lt;code&gt;/views&lt;/code&gt;. The second line set the view engine to ejs. Learn more about ejs &lt;a href="https://ejs.co/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next we use the &lt;code&gt;express-session&lt;/code&gt; middleware so that we can support persistent login from users. the session(options) receives an object of settings read the express-session documentation to learn &lt;a href="https://expressjs.com/en/resources/middleware/session.html" rel="noopener noreferrer"&gt;more&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The default server-side session storage, MemoryStore, is not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing. For a list of stores, see &lt;a href="https://expressjs.com/en/resources/middleware/session.html#compatible-session-stores" rel="noopener noreferrer"&gt;compatible session stores&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(
  session(
    { 
      secret: process.env.SESSION_SECRET, 
      resave: false, 
      saveUninitialized: false 
    }));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we redirect the user to the &lt;code&gt;localhost:8081/auth&lt;/code&gt; route once they visit &lt;code&gt;localhost:8081/&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/', function(req, res){
  res.redirect('/auth');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we configure two routers on the app for handling &lt;code&gt;localhost:8081/auth/*&lt;/code&gt; requests and the other for handling account request &lt;code&gt;localhost:8081/account/*&lt;/code&gt; these routers will be discussed next.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// set Routes
app.use('/auth', authRouter);
app.use('/account', accountRouter);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;export the express app&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = app;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating our Application Routers
&lt;/h2&gt;

&lt;p&gt;First, we create a route directory. The files in this directory will be used as route handlers to handle different routes in our application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Authentication Router&lt;/strong&gt;&lt;br&gt;
Create &lt;code&gt;auth.js&lt;/code&gt; file inside the &lt;code&gt;route&lt;/code&gt; directory, then import &lt;code&gt;express&lt;/code&gt;  and &lt;code&gt;passport&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const passport = require('passport');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We import &lt;code&gt;github&lt;/code&gt; which is an authentication middleware based on passport GitHub strategy this middleware will be explained later in this article. Also, import &lt;code&gt;authController&lt;/code&gt;. This module is meant to contain a bunch of functions that control user authentication but for now, it just contains the logout function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const github = require('./../utils/github');
const authController = require('./../controller/auth');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We configure passport to use the &lt;code&gt;github&lt;/code&gt; middleware.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;passport.use(github);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we use the &lt;code&gt;express.Router()&lt;/code&gt; class to create modular, mountable route handlers. then we use the &lt;code&gt;passport.initialize()&lt;/code&gt; function in the router this function is needed to initialize &lt;code&gt;passportjs&lt;/code&gt; on our routes, &lt;code&gt;passport.session()&lt;/code&gt; function enables persistent login with &lt;code&gt;passportjs&lt;/code&gt; in our route it handles session.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const router = express.Router();

router.use(passport.initialize());
router.use(passport.session());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;serializeUser&lt;/code&gt; determines which data of the user object should be stored in the session. The result of the &lt;code&gt;serializeUser&lt;/code&gt; function is attached to the session as &lt;code&gt;req.session.passport.user = {}&lt;/code&gt;. Here we store the whole user object&lt;/p&gt;

&lt;p&gt;The first argument of &lt;code&gt;deserializeUser&lt;/code&gt; corresponds to the user object that was given to the &lt;code&gt;done&lt;/code&gt; function.  The object is attached to the request object as &lt;code&gt;req.user&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(obj, done) {
    done(null, obj);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This line of code renders the &lt;code&gt;index.ejs&lt;/code&gt; file in the view directory once the user visits the &lt;code&gt;localhost:8081/auth&lt;/code&gt; route.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;router.get('/', function(req, res){
    res.render('index', { user: req.user });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This line of codes tries to authenticate the user with GitHub once the &lt;br&gt;
&lt;code&gt;localhost:8081/auth/github&lt;/code&gt; route is visited. It Redirect the user to a GitHub conscent page and request for the user authorization, once the user authorize the app, it redirects the user back to the callback url which is &lt;code&gt;localhost:8081/auth/github/callback&lt;/code&gt; for this application on successful login the user will be redirected to &lt;code&gt;localhost:8081/account&lt;/code&gt;  by this line of code &lt;code&gt;res.redirect('/account'));&lt;/code&gt; . &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;router.get('/github', passport.authenticate('github', { scope: [ 'user:email' ] }));

router.get('/github/callback', 
    passport.authenticate('github', { failureRedirect: '/' }),
    (req, res) =&amp;gt;  res.redirect('/account'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the user visit &lt;code&gt;localhost:8081/auth/logout&lt;/code&gt;. the session will be destroyed and the user will have to login again.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;router.get('/logout', authController.logout);

module.exports = router;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Create account routes&lt;/strong&gt;&lt;br&gt;
Create &lt;code&gt;account.js&lt;/code&gt; file inside the &lt;code&gt;route&lt;/code&gt; directory, the following codes below do the same function as the ones on &lt;code&gt;auth.js&lt;/code&gt; , &lt;code&gt;accountController.js&lt;/code&gt; contains functions for handling user accounts.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const passport = require('passport');
const accountController = require('./../controller/account');

const router = express.Router();

router.use(passport.initialize());
router.use(passport.session());

passport.serializeUser(function(user, done) {
    done(null, user);
});

passport.deserializeUser(function(obj, done) {
    done(null, obj);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This route handler, handles get requests sent to this route &lt;code&gt;localhost:8081/account&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;router.get('/', accountController.user);
module.exports = router;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Utility
&lt;/h2&gt;

&lt;p&gt;First, we create a &lt;code&gt;utils&lt;/code&gt; directory. This directory is going to contain all our utility functions, for this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create github middleware&lt;/strong&gt;&lt;br&gt;
This code exports a middleware this middleware is required when making an authentication request with &lt;code&gt;passport-github2&lt;/code&gt; strategy. Here we use passport-github2 strategy, we pass the configuration object which includes the &lt;code&gt;ClientId&lt;/code&gt;, &lt;code&gt;ClientSecret&lt;/code&gt;, and &lt;code&gt;CallbackUrl&lt;/code&gt;, these values should match the one used in creating the github application. if these values are correct and up to date the callback function with four parameters with be called&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accessToken - GitHub access Token&lt;/li&gt;
&lt;li&gt;refreshToken - GitHub refresh Token&lt;/li&gt;
&lt;li&gt;profile - contains user data gotten from GitHub&lt;/li&gt;
&lt;li&gt;done - this is callback function with two arguments error and data is called, the profile.id data is used to query the mongo database to check if the user account exists, if it doesn't exist the user is created with the data gotten from github.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;User.findOne({githubId: profile.id })&lt;/code&gt; checks if a user with the same &lt;code&gt;github&lt;/code&gt; profile exists in the database, if it does exist the &lt;code&gt;return done(null, data);&lt;/code&gt; function will be called with the user data. If no user exists the user will be created and the &lt;code&gt;return done(null, data);&lt;/code&gt; will be called with the user data.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const GitHubStrategy = require('passport-github2').Strategy;
const User = require('../model/UserModel');

module.exports = new GitHubStrategy({
    clientID: process.env.GITHUB_CLIENT_ID,
    clientSecret: process.env.GITHUB_CLIENT_SECRET,
    callbackURL: process.env.GITHUB_CALLBACK_URL
  },
  function(accessToken, refreshToken, profile, done) {

    User.findOne({githubId: profile.id }).then((data, err) =&amp;gt; {

      if (!data) return User.create({
        githubId: profile.id,
        fullname: profile.displayName,
        username: profile.username,
        location: profile._json.location,
        phone: profile._json.phone,
        email: profile._json.email,
        profilePhoto: profile._json.avatar_url
      }).then((data, err) =&amp;gt; {
        return done(null, data);
      });

      else return done(null, data);
    });
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Database Model
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;model&lt;/code&gt; directory. This directory is going to contain all our database Models, for this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create User Model&lt;/strong&gt;&lt;br&gt;
First, we create a &lt;code&gt;userModel.js&lt;/code&gt; file inside the &lt;code&gt;model&lt;/code&gt; directory, import &lt;code&gt;mongoose&lt;/code&gt; into the project, then create a user schema.&lt;/p&gt;

&lt;p&gt;Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.&lt;/p&gt;

&lt;p&gt;Models are fancy constructors compiled from &lt;code&gt;Schema&lt;/code&gt; definitions. An instance of a model is called a document. Models are responsible for creating and reading documents from the underlying MongoDB database.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose');

const userSchema = new mongoose.Schema(
  {
    fullname: { type: String },
    username: { type: String },
    githubId: { type: String, unique: true },
    location: { type: String },
    phone: { type: String },
    email: { type: String, lowercase: true },
    profilePhoto: { type: String, default: '' }
  },
  { timestamps: true }
);

const User = mongoose.model('User', userSchema);

module.exports = User;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Controllers
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;controller&lt;/code&gt; directory. This directory is going to contain all our controllers for this project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication controller&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;auth.js&lt;/code&gt; controller contains one function &lt;code&gt;logout&lt;/code&gt; to destroy user session and redirect user to the homepage.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.logout = (req, res, next) =&amp;gt; {
    req.logout();
    res.redirect('/');
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Authentication controller&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;account.js&lt;/code&gt; controller contains one function &lt;code&gt;user&lt;/code&gt;, &lt;code&gt;req.user&lt;/code&gt; get the user data from the request parameter, &lt;code&gt;if (!user) res.redirect('/');&lt;/code&gt; redirect the user to &lt;code&gt;localhost:8081/&lt;/code&gt; if the user exist it readers the &lt;code&gt;account.ejs&lt;/code&gt; templete.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.user = (req, res, next) =&amp;gt; {
    const user = req.user;

    if (!user) res.redirect('/');

    res.render('account', {user: user});
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating Views
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;views&lt;/code&gt; directory, this directory will hold all the ejs templating codes for the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Index ejs template&lt;/strong&gt;&lt;br&gt;
Create a file &lt;code&gt;index.ejs&lt;/code&gt; inside the &lt;code&gt;views&lt;/code&gt; directory. This templete renders a link to authenticate with github when user session is not available &lt;code&gt;&amp;lt;h2&amp;gt;Welcome! &amp;lt;a href="/auth/github"&amp;gt;Login with GitHub&amp;lt;/a&amp;gt; &amp;lt;/h2&amp;gt;&lt;/code&gt; and renders a link to view user account, when user session is available &lt;code&gt;&amp;lt;h2&amp;gt;Hello, &amp;lt;%= user.fullname %&amp;gt; &amp;lt;a href="/account"&amp;gt;View Account&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;% if (!user) { %&amp;gt;
    &amp;lt;h2&amp;gt;Welcome! &amp;lt;a href="/auth/github"&amp;gt;Login with GitHub&amp;lt;/a&amp;gt; &amp;lt;/h2&amp;gt;
&amp;lt;% } else { %&amp;gt;
    &amp;lt;h2&amp;gt;Hello, &amp;lt;%= user.fullname %&amp;gt; &amp;lt;a href="/account"&amp;gt;View Account&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;% } %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Create the Account ejs template&lt;/strong&gt;&lt;br&gt;
Create a file &lt;code&gt;account.ejs&lt;/code&gt; inside the &lt;code&gt;views&lt;/code&gt; directory. This template simply displays user information, stored in the database.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;&lt;br&gt;
    &amp;lt;p&amp;gt;Full Name: &amp;lt;%= user.fullname %&amp;gt;&amp;lt;/p&amp;gt;&lt;br&gt;
    &amp;lt;p&amp;gt;Username: &amp;lt;%= user.username %&amp;gt;&amp;lt;/p&amp;gt;&lt;br&gt;
    &amp;lt;p&amp;gt;Email: &amp;lt;%= user.email %&amp;gt;&amp;lt;/p&amp;gt;&lt;br&gt;
    &amp;lt;p&amp;gt;location: &amp;lt;%= user.location %&amp;gt;&amp;lt;/p&amp;gt;&lt;br&gt;
    &amp;lt;p&amp;gt;&amp;lt;a href="/auth/logout"&amp;gt;Logout &amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br&gt;
    &amp;lt;img src=&amp;lt;%= user.profilePhoto %&amp;gt; /&amp;gt;&lt;br&gt;
&amp;lt;/div&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;In this article you have learned how to authenticate users, using &lt;code&gt;passport-github2&lt;/code&gt; strategy, You learned how to create and configure a github application, and maintain user sessions within your application while using ejs as templating engine. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>mongodb</category>
      <category>node</category>
      <category>github</category>
    </item>
  </channel>
</rss>
