<?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: Nwachukwu Chibuike</title>
    <description>The latest articles on DEV Community by Nwachukwu Chibuike (@chyke007).</description>
    <link>https://dev.to/chyke007</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%2F535378%2Fde3331f3-0118-4745-b34a-9908895cb5c0.png</url>
      <title>DEV Community: Nwachukwu Chibuike</title>
      <link>https://dev.to/chyke007</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chyke007"/>
    <language>en</language>
    <item>
      <title>Backends For Frontends — My Take</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Wed, 07 Jun 2023 14:48:19 +0000</pubDate>
      <link>https://dev.to/aws-builders/backends-for-frontends-my-take-2n0m</link>
      <guid>https://dev.to/aws-builders/backends-for-frontends-my-take-2n0m</guid>
      <description>&lt;h2&gt;
  
  
  Backends For Frontends — My Take
&lt;/h2&gt;

&lt;p&gt;What do you get when you have a lot of Microservices to fetch data from before displaying a result — Multiple network calls; add the need to display results based on the requesting client and it becomes a dilemma.&lt;/p&gt;

&lt;p&gt;Solution? &lt;strong&gt;Backends For Frontends&lt;/strong&gt;(BFF)&lt;/p&gt;

&lt;p&gt;In this article, we would get to know about what the Backends For Frontends pattern is about, why it came about, the problems it seeks to solve when to use it, and its rewards. Let's get right into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Monolith vs Microservices Architecture
&lt;/h2&gt;

&lt;p&gt;Initially, applications were built using the Monolith architecture approach. Here all application components are bundled and deployed as a single unit.&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AH9sp6P59FCbGvDhb.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AH9sp6P59FCbGvDhb.png" alt="Monolith Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One single source code contains the application and handles everything and is hosted on a server, clients connect to this server and get results.&lt;/p&gt;

&lt;p&gt;This single application contains the APIs, UI, Data Access Layers, CronJobs, etc all in one. This brought some advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick deployment&lt;/strong&gt;: Simple and faster deployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier testing&lt;/strong&gt;: Since the whole source code resides in one place, it makes it easier to debug and carry out automated tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster Development&lt;/strong&gt;: Since there are fewer moving parts, all efforts are focused on a single source code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this approach came with some headaches, because all the technology and services were locked into one single large project and deployed, and software engineering teams, had to deal with issues like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Poor Fault Tolerance&lt;/strong&gt;: Once the application goes down, all components are affected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technology lockdown&lt;/strong&gt;: Application built with a single language, even when some parts of the application would have faired better been programmed using another language.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;: Difficult to maintain as there are a lot of tightly coupled parts, a minor update in a component could lead to a breaking change in another component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: The need to scale the whole application which increases the cost when only a particular section of the application requires scaling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then came Microservice, where each of the services is broken down into separate services that have a well-defined domain. Clients connect to these microservices, fetch information, and display. This solves the issues experienced in Monolith.&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ALAW0hvXhTWDRbnof.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ALAW0hvXhTWDRbnof.png" alt="Microservices Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brought great advantages like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Agile Development,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved Scalability,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technological Flexibility,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved Fault Tolerance&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However as can be seen from the image above, the client now connects to multiple servers to get the information it requires. This adds additional work for the clients as it has to make multiple calls to get the data it needs to display a result, as well as do more data manipulation and formatting on its end to suit what it needs.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Backends For Frontends&lt;/strong&gt; pattern comes in handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Backends For Frontends Pattern?
&lt;/h2&gt;

&lt;p&gt;It is a layer that sits between the Backend(Microservices) and the client, it acts as an aggregator and an additional layer of abstraction.&lt;/p&gt;

&lt;p&gt;Every client be it mobile, desktop, IoT devices, and wearables would have a separate BFF that communicates with the different microservices, filters out unwanted data, and formats the response in a way needed by the client.&lt;/p&gt;

&lt;p&gt;The diagram below gotten from &lt;a href="https://samnewman.io/patterns/architectural/bff/" rel="noopener noreferrer"&gt;Sam Newman's&lt;/a&gt; webpage shows a great visual about this pattern in use. He emphasizes the need for having one BFF per user experience.&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AR01mDJYjGbMfv5BI.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AR01mDJYjGbMfv5BI.jpg" alt="BFF Pattern"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This improves the performance of the overall application as it reduces network calls the client needs to make before it gets the data it needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of using Backends For Frontends
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduces network calls from the client side&lt;/strong&gt;: The Client doesn't need to communicate to multiple endpoints/microservices to get all the data it needs to display. This data aggregating task is now handed over to the BFFs server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fewer client data manipulation&lt;/strong&gt;: Each client BFF handles data fetching, manipulation, and aggregation as needed for the client. This removes the need from the client end to perform this data manipulation to display a unique view to the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: An additional layer can also act as a filter removing some fields which exist in each microservice endpoint response that may not be needed for a particular client. This further improves the security of the overall architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separation of concerns&lt;/strong&gt;: There is a saying that “Backends tend to live longer than Frontends” hence we shouldn't introduce frontend requirements directly into the backend. This makes it easier for maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Removes the need to update client response when a new API version is released to a microservice&lt;/strong&gt;: Since the BFFs act as a layer of abstraction, updates to the underlying API(Microservices) endpoint won't require a change on the client end, as the BFF acts as the source for the client and not the API directly. Hence BFF maintains the endpoints response format it provides to the client while it does the update internally on how it communicates with the Microservices due to the newly released API versions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges of using Backends For Frontends
&lt;/h2&gt;

&lt;p&gt;With all the good intentions this pattern has, it introduces some concerns which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: One point of attack, since the client only communicates with the BFF, makes it an easier target and once down the client won't be able to fetch the results it needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increase in network latency&lt;/strong&gt;: Due to the multiple network hops made before a request is sent back to the client, there is some network latency introduced.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Additional Code maintenance&lt;/strong&gt;: It introduces an additional piece of code that has to be developed, maintained, deployed, and monitored.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to use the Backends For Frontends Pattern
&lt;/h2&gt;

&lt;p&gt;The deciding factor here is the client. The moment you need to provide unique functionality for a particular client say a mobile UI, Web App, or third party, then it is strongly advised to consider using BFFs for each client.&lt;/p&gt;

&lt;p&gt;That is when the interface between different clients varies significantly, a BFF is your best option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difference between Backends For Frontends and API Gateway
&lt;/h2&gt;

&lt;p&gt;I added this section because as I learned about the BFF pattern I found some overlap with the API gateway.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A standard API gateway handles requests from all the clients interacting with the system, while a BFF only handles a specific client.”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;The Backends For Frontends is a natural evolution of Microservices Architecture, it’s a pattern created with the clients in mind and also the user's experience.&lt;/p&gt;

&lt;p&gt;I look forward to seeing this pattern used more within the tech ecosystem and can't wait to see what you build with it!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>microservices</category>
      <category>scalability</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Deploy a Node.Js Cloud Native Application to Amazon EKS</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Sun, 21 May 2023 10:30:59 +0000</pubDate>
      <link>https://dev.to/aws-builders/deploy-a-nodejs-cloud-native-application-to-amazon-eks-7ij</link>
      <guid>https://dev.to/aws-builders/deploy-a-nodejs-cloud-native-application-to-amazon-eks-7ij</guid>
      <description>&lt;p&gt;In this article, I show how to deploy a Cloud Native Node.js application to Amazon EKS via the AWS CLI. Amazon Elastic Container Registry(ECR) is used to store the built docker images.&lt;/p&gt;

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

&lt;p&gt;To better follow along with this article, you would need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; 12 or above&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NPM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS CLI configured on your local machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://aws.amazon.com/console/"&gt;AWS&lt;/a&gt; account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker installed on your local machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Knowledge of Kubernetes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Amazon EKS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon&lt;/strong&gt; &lt;strong&gt;Elastic Kubernetes Service&lt;/strong&gt; (&lt;strong&gt;EKS&lt;/strong&gt;) is a managed Kubernetes service to run Kubernetes in the AWS cloud and on-premises data centers. As an AWS-managed service, it makes it easy to use Kubernetes on AWS without needing to install and operate the Kubernetes control plane.&lt;/p&gt;

&lt;p&gt;We would make use of EKS to deploy the cloud-native app we use in this article.&lt;/p&gt;

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

&lt;p&gt;Here we set up the project, dockerize it and run it locally to make sure everything works as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Node.js project
&lt;/h3&gt;

&lt;p&gt;We would proceed to clone an already existing application found &lt;a href="https://github.com/kkohtaka/webapp-nodejs"&gt;here&lt;/a&gt;. It spins up an express server that serves some dummy content.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Clone this repository
$ git clone https://github.com/kkohtaka/webapp-nodejs.git
# Go into the repository
$ cd webapp-nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Containerizing the project
&lt;/h3&gt;

&lt;p&gt;To containerize the project, we would make use of &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;. First, we create a Dockerfile for the application.&lt;/p&gt;

&lt;p&gt;In the root folder, create a file named Dockerfile and add the following content within it:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:14
WORKDIR /app
COPY package.json ./
RUN npm install 
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, create a .dockerignore file:&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;To build the docker image for the application run the following command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t demo/webapp-nodejs .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To verify the image is built well, spin up a container to test by running the built docker image:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 3000:3000 demo/webapp-nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command above enables us to test the application in a local browser by visiting &lt;a href="http://localhost:3000/"&gt;http://localhost:3000&lt;/a&gt;. The image below confirms it works as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t5eNfC6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Am1phkTDlMnvQd9Hg0wS1Qw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t5eNfC6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Am1phkTDlMnvQd9Hg0wS1Qw.png" alt="Running app" width="592" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing image to Amazon Elastic Container Registry(ECR)
&lt;/h2&gt;

&lt;p&gt;In other to make the built docker image publicly available, we need to push it to a central repo. We would make use of &lt;a href="https://aws.amazon.com/ecr/"&gt;Amazon ECR&lt;/a&gt; to store the image.&lt;/p&gt;

&lt;p&gt;First, create the Amazon ECR registry where we would store the image. Run the command below to do that&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws ecr-public create-repository --repository-name webapp-nodejs-repo --region us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The command connects to AWS using the default AWS profile we have configured and creates the repository. It outputs a JSON-like response containing the details of the newly created repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NuhylHKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2556/1%2ASK9qbhzyKwnF-FXjDTvawQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NuhylHKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2556/1%2ASK9qbhzyKwnF-FXjDTvawQ.png" alt="" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, authenticate our local machine docker client to the Amazon ECR registry. This gives access to the registry for up to 12hrs, read more about this &lt;a href="https://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-push-ecr-image.html"&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;aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Proceed to tag the local docker image with the ECR Registry.&lt;/p&gt;

&lt;p&gt;Replace REPO_URI with Repository URI gotten from ECR when the registry was created. In my case it is: public.ecr.aws/d5d5p5r5/webapp-nodejs-repo&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker tag demo/webapp-nodejs:latest &amp;lt;REPO_URI&amp;gt;:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, push the image to the ECR repository:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push &amp;lt;REPO_URI&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w6svcKbj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3092/1%2Ai-1ZZEeZUeqJjs6N6AjoPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w6svcKbj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3092/1%2Ai-1ZZEeZUeqJjs6N6AjoPg.png" alt="docker push" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: We can also configure the Default region name using &lt;strong&gt;aws configure&lt;/strong&gt; for the default profile to be us-east-1 instead of having to include it in every command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provisioning an EKS Cluster
&lt;/h2&gt;

&lt;p&gt;Now that the image has been deployed to ECR, creating an EKS cluster where the app would be deployed is the next thing to do.&lt;/p&gt;

&lt;p&gt;We make use of the eksctl CLI to create the cluster in EKS, eksctl which is a simple command-line tool for creating and managing Kubernetes clusters on Amazon EKS.&lt;/p&gt;

&lt;p&gt;First, we need to install this CLI to be able to use it, head over to this &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html"&gt;page&lt;/a&gt; to learn how to install it based on your device. After, run the command below to confirm if you have it all set up.&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;If you get a version shown, then all is well, else go back to the referenced page to identify any step you may have missed.&lt;/p&gt;

&lt;p&gt;Now we have configured eksctl, we now provision our first cluster(creating the cluster in the us-east-2 region):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl create cluster --name webapp-nodejs-cluster --region us-east-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ibEaBa3I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3536/1%2AXI-3v7HykYuZkvBpslph_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ibEaBa3I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3536/1%2AXI-3v7HykYuZkvBpslph_g.png" alt="eksctl create cluster" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, configure kubectl to enable it to connect to the EKS cluster by updating the kubectl config (update-kubeconfig) with the cluster endpoint.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws eks update-kubeconfig --name webapp-nodejs-cluster --region us-east-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Deploying to EKS Cluster
&lt;/h2&gt;

&lt;p&gt;At this stage, we have an image in ECR and an empty EKS Cluster running, the last step is to run the application within this EKS Cluster.&lt;/p&gt;

&lt;p&gt;To deploy the application, create a Deployment.yml file containing the deployment details. The deployment creates a &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/"&gt;Pod&lt;/a&gt;, where the application runs in a single container using the Docker image.&lt;/p&gt;

&lt;p&gt;Replace the image “public.ecr.aws/d5d5p5r5/webapp-nodejs-repo” with your ECR URI:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-nodejs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-nodejs
  template:
    metadata:
      labels:
        app: webapp-nodejs
    spec:
      containers:
      - name: webapp-nodejs
        image: public.ecr.aws/d5d5p5r5/webapp-nodejs-repo:latest
        ports:
          - containerPort: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, apply the deployment to create it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f Deployment.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To verify if it works, run the command below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OSZMjUUy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2208/1%2AZUnqrM_1K1H3LYyhX4Bzhw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OSZMjUUy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2208/1%2AZUnqrM_1K1H3LYyhX4Bzhw.png" alt="" width="800" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now need to expose the pods running within the cluster to the outside world to be accessible. To do this we need to create a Service with the type of &lt;strong&gt;Load Balancer&lt;/strong&gt; to expose the port the application is listening to.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl expose deployment webapp-nodejs --port=80 --target-port=3000 --type=LoadBalancer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To verify if it works, run the command below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D2WqxgkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3656/1%2AKitw3LAcCi4vMivr6OU4Dg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D2WqxgkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3656/1%2AKitw3LAcCi4vMivr6OU4Dg.png" alt="get services" width="800" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Finally, to confirm everything works as expected, copy the exposed **EXTERNAL-IP **address shown in the previous command and visit a browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RCdLAeqw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3196/1%2A0q54Iivhzsn3FzlNMCPMoA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RCdLAeqw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3196/1%2A0q54Iivhzsn3FzlNMCPMoA.png" alt="" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! it works as expected!&lt;/p&gt;

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

&lt;p&gt;In this article, you learned how to Dockerize a Node.js application, push the built image to &lt;strong&gt;Amazon Elastic Container Registry (ECR)&lt;/strong&gt;, created an &lt;strong&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/strong&gt; cluster, deployed the application within the cluster, and finally exposed the deployment so we could test it.&lt;/p&gt;

&lt;p&gt;Amazon EKS makes it easy and super fast to deploy cloud native applications, try using it for your next deployment!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>node</category>
      <category>docker</category>
    </item>
    <item>
      <title>Serverless Facial Recognition Voting Application Using AWS Services</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Wed, 03 May 2023 12:18:39 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-facial-recognition-voting-application-using-aws-services-n26</link>
      <guid>https://dev.to/aws-builders/serverless-facial-recognition-voting-application-using-aws-services-n26</guid>
      <description>&lt;p&gt;Recently I watched the recorded &lt;a href="https://www.youtube.com/watch?v=qs0U0LdNkV0"&gt;video&lt;/a&gt; of the Serverlesspresso team talk at 2022 Reinvent on the AWS Events Youtube Page. I got inspired and decided to take a cue from that video and other lessons from 2022 Reinvent and build an open-source project.&lt;/p&gt;

&lt;p&gt;The result? FacePolls, a Serverless Facial Recognition Voting Application built entirely using AWS services, adheres to established best practices and uses the Event-Driven pattern.&lt;/p&gt;

&lt;p&gt;This article describes how I built this project from scratch, the patterns I used and why, my key takeaways and learnings, and finally a call to action to build event-driven and serverless systems.&lt;/p&gt;

&lt;p&gt;Let’s get right into it!&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; 16&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NPM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An AWS account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS CLI configured on your local machine with an AWS profile, would be used for deploying the backend section of the application, which was built using the Serverless Framework&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Serverless installed globally, would be used to run the serverless deploy command&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;First, you would need to clone the repo found &lt;a href="https://github.com/chyke007/facial-vote"&gt;here&lt;/a&gt;(Feel free to leave a star or fork it).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
    # Clone this repository
    git clone https://github.com/chyke007/facial-vote.git

    # Go into the repository
    cd facial-vote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Frontend Application &amp;amp; Admin Frontend Application
&lt;/h3&gt;

&lt;p&gt;Now inside the project folder, we can easily run both apps as they are built using Next.js. To run it locally, you would need to install the packages used, as well as create a .env file from the .env.example sample file provided, then provide the right values.&lt;br&gt;
&lt;/p&gt;

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

    # Copy environment variable
    $ cp facial-vote-admin/.env.example .env &amp;amp;&amp;amp; cp facial-vote-frontend/.env.example facial-vote-frontend/.env

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

&lt;/div&gt;



&lt;p&gt;You should get the necessary values once the backend application is deployed, to get the necessary endpoints.&lt;br&gt;
&lt;/p&gt;

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

    # Run Frontend (run from folder root)
    $ cd facial-vote-frontend &amp;amp;&amp;amp; npm i &amp;amp;&amp;amp; npm run dev

    # Run Admin (run from folder root)
    $ cd facial-vote-admin &amp;amp;&amp;amp; npm i &amp;amp;&amp;amp; npm run dev

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

&lt;/div&gt;



&lt;p&gt;You could also deploy it to AWS Amplify, by connecting your fork of the repo, providing the necessary environment variables, and deploying the application.&lt;/p&gt;

&lt;p&gt;Other providers like Vercel can also be used to quickly deploy the frontend and admin section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend Application
&lt;/h3&gt;

&lt;p&gt;Contains the backend/serverless part of the application built using the &lt;a href="https://www.serverless.com/"&gt;Serverless Framework&lt;/a&gt;. Simply create the .env file with the right values and deploy the app to your AWS account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
    # Copy environment variable
    $ cp facial-vote-backend/.env.example facial-vote-backend/.env 

    # Deploy backend (run from folder root)
    $ npm i serverless -g
    $ cd facial-vote-backend &amp;amp;&amp;amp; serverless deploy

    # Remove backend resources (run from folder root)
    $ cd facial-vote-backend &amp;amp;&amp;amp; sls remove
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AWS Services used
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/amplify/"&gt;AWS Amplify&lt;/a&gt;: Used in the frontend to manage users authentication and acts as a point of contact between the frontend and AWS services like S3, IoT, and Cognito&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/cognito/"&gt;Amazon Cognito&lt;/a&gt;: Handled Authentication and management of users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/eventbridge/"&gt;Amazon EventBridge&lt;/a&gt;: Acted as a link between services. Choreographed the movement of events between some AWS services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/rekognition/"&gt;Amazon Rekognition&lt;/a&gt;: Used to index, detect faces in the picture, and compare faces when users try voting, it was the heart of the facial voting feature.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt;: Lambda function used to run server codes and application logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/ses/"&gt;Amazon SES&lt;/a&gt;: Used to send OTP codes during the user account retrieval step.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/iot-core"&gt;AWS IoT&lt;/a&gt;: For real-time communication between the server and the frontend application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/step-functions/"&gt;AWS Step Functions&lt;/a&gt;: Acted as the orchestrator and brain of the application business logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/pm/dynamodb/"&gt;Amazon DynamoDB&lt;/a&gt;: Used as the Database service owning to its Schemaless/Nosql design, Serverless nature, fast and highly scalable nature.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/pm/serv-s3/"&gt;Amazon S3&lt;/a&gt;: Was used as storage for the uploaded faces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/api-gateway/"&gt;Amazon API Gateway&lt;/a&gt;: Used for API management and endpoint creation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudformation/"&gt;AWS CloudFormation&lt;/a&gt;: Used to provision resources used by Serverless Framework and the application in general.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html"&gt;AWS STS&lt;/a&gt;: Used to generate temporal credentials.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Other Technology used
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt;: Used to build the frontend application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.serverless.com/"&gt;Serverless Framework&lt;/a&gt;: Choose this over the AWS SAM, as I am more familiar with it, and seems easier to use.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The following below details how the application works, it is broken into 4 sections, which are:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A. Face Index Flow&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Frontend was created using Next.js and hosted on Amplify (and Vercel). New users enter their email to retrieve their account(Admin has created users by adding users' email to the Cognito user pool).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the email is found, a custom challenge for authentication is fired, it sends an OTP using SES to users' email to verify they own the email they are claiming. Once OTP is correct, a new step is shown to upload their face to attach it to their retrieved email.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user then uploads their face photo, it goes to a private folder in S3, which has an EventBridge integration with a lambda function, this function gets the object details and initializes the Index Face Step function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each Step function task gets the object details and does its work, the first task makes sure it is a face that was uploaded using Rekognition, and the second task checks if a face exists already in Rekognition collection and prevents users from proceeding if a face is found, the third task indexes the face to Rekognition and the last saves the new Face entry record to DynamoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS IoT is used to relay real-time feedback to the user on how each stage goes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  B. Face Recognition / Vote Flow
&lt;/h3&gt;

&lt;p&gt;This flow was the most complex of the 4 I had to deal with. As I needed to make it as secure as possible while still maintaining speed and efficiency.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Users use the application to upload their faces image to a public folder in the S3 bucket.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user is subscribed to the custom image name generated before uploading to S3.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EventBridge trigger watches that folder and calls the lambda function integrated. This function then initializes the CompareFace Step Function with the object details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Step Function tasks do the following: validate it's a face that was uploaded, check if the face is found in the Amazon Rekognition collection, and if it's found, it calls the next task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It fetches the user's email and sends an OTP, this serves as a 2FA to prevent a user from using another registered user's face to vote. Then it calls the next task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This task is a lambda function that generates a 15mins(configurable from .env) STS credential that has permission to invoke API Gateway and is sent back to the user using AWS IoT.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS IoT publishes the STS credentials, encrypted user id, and encrypted Otp to the custom image name topic user is already subscribed to. This way only a specific user gets the message, the user who uploaded the image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The frontend application gets the message using Amplify and then fetches all categories that can be voted in. (This API endpoint is only secured with an API key, and not AWS IAM, as it isn't a private endpoint)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user then proceeds to call the vote endpoint to add their vote, this endpoint is secured using API Key and AWS IAM. The generated STS credential is then signed and used to authenticate this request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The add/validate vote lambda function validates the vote details and then adds the vote to DynamoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DynamoDB Stream is configured for the DynamoDB table, hence it sends this new vote to the stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Lambda function is listening to the stream &lt;strong&gt;INSERT&lt;/strong&gt; method for &lt;strong&gt;PK&lt;/strong&gt; starting with &lt;strong&gt;VOTES&lt;/strong&gt; and processes the vote details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then it uses AWS IoT to publish the processed result to the &lt;strong&gt;VOTE_ADDED&lt;/strong&gt; topic, which users on the Live Result page are subscribed to so they see the vote coming in real time!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  C. Live Result
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;From the frontend application, the user navigates to the live result page, which subscribes the user to a &lt;strong&gt;VOTE_ADDED&lt;/strong&gt; topic which is published once a vote is added to DynamoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Selects the category they want to see the result, and then the result they requested is shown.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once a new vote is added to DynamoDB, it uses DynamoDB streams to stream the new record to a Lambda function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This function(same as in B above) then processes the record and publishes the result using AWS IoT to the &lt;strong&gt;VOTE_ADDED&lt;/strong&gt; topic the user already subscribed to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS IoT relays this information to Amplify and this results in an update to the UI in real time without the need to refresh the page!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  D. Admin Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Creates users and voting categories using the Next.js application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Currently only secured using API key, but should implement more security&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Took me around 4–5 days to come up with the architecture below, I factored in ease of use, security, cost, scalability, and efficiency as I designed it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Face Index Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xCSyt4v_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A57dLJalaQlRaud9RbAnmMQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xCSyt4v_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A57dLJalaQlRaud9RbAnmMQ.png" alt="Face Index Flow" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Face Recognition/Voting Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N24nfOyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2114/1%2A6OjSkszV9eHdqcgsfZOF9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N24nfOyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2114/1%2A6OjSkszV9eHdqcgsfZOF9g.png" alt="Face Recognition/Voting Flow" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Result Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xt3NbEia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ABlQMJYjIkx5Va_nLW_UZqA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xt3NbEia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2ABlQMJYjIkx5Va_nLW_UZqA.png" alt="Live Result flow" width="636" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5jBnVS-J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A99KxUegqmZYMfis63XL9-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5jBnVS-J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A99KxUegqmZYMfis63XL9-Q.png" alt="Admin Flow" width="490" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Functions
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a7s6tBWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaiqiQTVIzXy_T3hns2lIVw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a7s6tBWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AaiqiQTVIzXy_T3hns2lIVw.png" alt="IndexFace Machine" width="270" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zQydGIrL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Akhs9vY-D_QNbsVqgiZH7MA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zQydGIrL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Akhs9vY-D_QNbsVqgiZH7MA.png" alt="CompareFace Machine" width="215" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB Schema
&lt;/h2&gt;

&lt;p&gt;Architecting the DynamoDB schema was another exciting part of this project. I used the Single-Table Design approach and learned this from a previous role I worked in, and also from Alex Debries' write-ups on it.&lt;/p&gt;

&lt;p&gt;For further reading on this concept, I recommend reading Alex Debrie’s article where he wrote a detailed write-up on &lt;a href="https://www.alexdebrie.com/posts/dynamodb-single-table/#what-is-single-table-design"&gt;this&lt;/a&gt;, as well as AWS ReInvent 2020 talk he gave &lt;a href="https://www.youtube.com/watch?v=fiP2e-g-r4g"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also check out an article I wrote &lt;a href="https://medium.com/faun/whats-the-fuss-about-dynamodb-single-table-design-my-take-5209670510e6"&gt;here&lt;/a&gt; about this architectural pattern here.&lt;/p&gt;

&lt;p&gt;I made use of a composite primary key(Partition and Sort key) and the table had 1 Global Secondary Index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PK&lt;/strong&gt;: Partition Key, &lt;strong&gt;SK&lt;/strong&gt;: Sort Key, &lt;strong&gt;GS1PK&lt;/strong&gt;: Global Secondary Index Partition key, &lt;strong&gt;GS1SK&lt;/strong&gt;: Global Secondary Index Sort key&lt;/p&gt;

&lt;h3&gt;
  
  
  Voting/ Vote Category
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PK&lt;/strong&gt;: VOTING#status&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SK&lt;/strong&gt;: voting_id#voting_name&lt;/p&gt;

&lt;h3&gt;
  
  
  Votes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PK&lt;/strong&gt;: VOTES#voting_id&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SK&lt;/strong&gt;: face_id#candidate_id&lt;/p&gt;

&lt;h3&gt;
  
  
  Face Entry
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PK&lt;/strong&gt;: FACE_ENTRY#user_email&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SK&lt;/strong&gt;: face_id#uploaded_image_key&lt;/p&gt;

&lt;p&gt;The Face Entry also has a GSI, which is stored when creating a new face entry:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GS1PK&lt;/strong&gt;: FACE_ENTRY#face_id,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GS1SK&lt;/strong&gt;: user_email#uploaded_image_key&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost&lt;/strong&gt;: Throughout the 2 weeks I spent developing the application (Immediately deployed the app using serverless from day 1 and updated it as I made changes) and 2 days of testing the full process with some of my friends, I noticed the cost was still kept at a record low. The total during this period was a record low of 1.37 USD spent!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging:&lt;/strong&gt; Required a lot, and was helpful. Helped me catch a particular issue when the DynamoDB stream kept retrying as the Lambda function wasn't fully set up to process it, caught it on the 50th retry using Lumigo and Cloudwatch, had I not, it could have retired 10000 times, Yikes! Another helpful service here was Step Functions, as I could see input and output on each step and also replay the function with new or the same old parameters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;**Permission issues: **An example is the lambda function that calls the Amazon Rekognition method to index, compare or save a face, it needed to have permission to access S3. I had a challenging time figuring this out as I thought that since it was Rekognition, it should have all permissions and not necessarily the Lambda function that calls it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why I choose this approach
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Realtime updates:&lt;/strong&gt; I needed real-time updates as key events occurred, like a user voting, other viewers on the live result page needed to see this new input reflect immediately without the need to reload their pages. AWS IoT, DynamoDB, DynamoDB streams, and Lambda were the best combinations I could think of, and they delivered!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost-Effective&lt;/strong&gt;: Lambda, API Gateway, SES.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service orchestration&lt;/strong&gt;: Step Functions it was!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serverless and Event-Driven&lt;/strong&gt;: S3, EventBridge, DynamoDB, and AWS IoT were the key services here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced engineering effort&lt;/strong&gt;: Amazon Rekognition, AWS IoT, Cognito, and Amplify really shone in this part.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easier management&lt;/strong&gt;: API Gateway, CloudFormation, and Cognito were the key services here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: STS and Cognito were the key services here.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Embarking on this project was a great opportunity to implement lots of best practices I had learned from work and also from preparing and getting multiple AWS certificates.&lt;/p&gt;

&lt;p&gt;Completing it makes me more confident of my AWS and cloud skills and I look forward to creating more of these as time permits.&lt;/p&gt;

&lt;p&gt;I encourage you to consider using the event-driven and serverless architecture in your next project as it makes development seamless and efficient.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>eventdriven</category>
      <category>aws</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Build a WhatsApp Chatbot Voting Application Using NodeJs and Twilio</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Thu, 16 Mar 2023 14:07:32 +0000</pubDate>
      <link>https://dev.to/aws-builders/build-a-whatsapp-chatbot-voting-application-using-nodejs-and-twilio-1hl6</link>
      <guid>https://dev.to/aws-builders/build-a-whatsapp-chatbot-voting-application-using-nodejs-and-twilio-1hl6</guid>
      <description>&lt;h2&gt;
  
  
  Build a WhatsApp Chatbot Voting Application Using NodeJs and Twilio
&lt;/h2&gt;

&lt;p&gt;With the rate of technological advancement taking place in this century, we are always finding new ways to automate our tasks and make our lives better. Chatbots help us reduce our dependence on our manual ways of communication and also challenges our preconceived way of implementing solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a ChatBot?
&lt;/h2&gt;

&lt;p&gt;In its mere definition, it is a software application used to conduct an online chat conversation via text or text-to-speech, in place of providing direct contact with a live human agent. It has been used in different contexts ranging from customer support, book tickets for movie/show, banking(UBA Leo) just to mention a few. Its use can only be limited by our creativity!&lt;/p&gt;

&lt;p&gt;In this tutorial, we would be embarking on a creativity journey by building a voting WhatsApp Chatbot with NodeJs using the Twilio Platform.&lt;/p&gt;

&lt;p&gt;After successfully following this tutorial, you would have learned how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;respond to WhatsApp messages sent to your Twilio WhatsApp number&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;develop a Rest API based voting application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;send free-form messages using the Twilio WhatsApp API&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;To successfully follow through with this tutorial the following are required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Basic knowledge of NodeJs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NodeJs and Npm installed on your machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A WhatsApp enabled Twilio number&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Twilio Account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An installation of &lt;a href="https://ngrok.com/product" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup and Installation
&lt;/h2&gt;

&lt;p&gt;We would make use of Nodejs. Start by creating a directory, then cd into it and run this command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir e-voting &amp;amp;&amp;amp; cd e-voting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then we initialize a node project by creating a package.json, the command allows the creation of the file without us entering prompt values. You can later change the values in this file.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm init -y 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Next, we proceed to install the packages we would be using&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i express twilio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Express — We use to set up our server&lt;/p&gt;

&lt;p&gt;Twilio — The Twilio Library we would use to send messages&lt;/p&gt;

&lt;p&gt;Now that we have our environment set up, let's proceed to our Twilio &lt;a href="https://www.twilio.com/console/sms/whatsapp/learn" rel="noopener noreferrer"&gt;sandbox&lt;/a&gt; to set things up.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up the WhatsApp Sandbox
&lt;/h2&gt;

&lt;p&gt;In other to give our chatbot access to the messages from WhatsApp, Twilio provides a very robust &lt;a href="https://www.twilio.com/whatsapp" rel="noopener noreferrer"&gt;WhatsApp API&lt;/a&gt; that allows us to both send and receive WhatsApp messages right from within our application.&lt;/p&gt;

&lt;p&gt;However before we can start sending and receiving messages using the Twilio WhatsApp API in production, we must first get a &lt;a href="https://www.twilio.com/whatsapp/request-access" rel="noopener noreferrer"&gt;WhatsApp Approved Twilio Number&lt;/a&gt; which will act as our WhatsApp number for sending and receiving messages. For this tutorial we would not involve ourselves in that process, we would rather leverage on a safe &lt;a href="https://www.twilio.com/console/sms/whatsapp/learn" rel="noopener noreferrer"&gt;sandbox&lt;/a&gt; Twilio provides for development and testing purposes.&lt;/p&gt;

&lt;p&gt;To begin using the Twilio WhatsApp Sandbox, we proceed to the &lt;a href="https://www.twilio.com/console/sms/whatsapp/learn" rel="noopener noreferrer"&gt;WhatsApp section&lt;/a&gt; on the Twilio dashboard and send a message to the sandbox number provided; usually, +14155238886 with the provided code, which is in the format join-{unique word}:&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%2Fcdn-images-1.medium.com%2Fmax%2F2732%2F1%2AlqGb0hDYQmc6sJ18Ltxbbw.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%2Fcdn-images-1.medium.com%2Fmax%2F2732%2F1%2AlqGb0hDYQmc6sJ18Ltxbbw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should receive a response similar to the one below once you join. If you didn't check the process you followed to make sure you didn't miss any step.&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AXslwAxlsILNzK5EeXYWl_g.jpeg" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AXslwAxlsILNzK5EeXYWl_g.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the App
&lt;/h2&gt;

&lt;p&gt;From the installation, we have only a package.json file in our project. We would then create a new file called index.js which would be used to set up our application server(with expressjs)&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
The above simply uses express to spin up a server and uses a route file which was imported on line 2. We would later send all request to our server on the &lt;strong&gt;/vote&lt;/strong&gt; route which points to this external route file.&lt;/p&gt;

&lt;p&gt;Next, we proceed to create a routes.js which would hold the logic&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
I know this file looks quite a lot but with some explanation, you would see it's not that complex. To make the explanation easier I would be explaining section by section.

&lt;p&gt;The &lt;strong&gt;First Section&lt;/strong&gt; spans from Line1–5 is where we install helpers files and methods into our application. At Line 3, we installed the Twilio official NodeJs module which we would use to send back our response. Line 4 we imported our helper response module(this would help format our various responses). Line 5, sees us introduce our utility module where we store our helper functions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Second Section&lt;/strong&gt; spans from Line 7–25 is where we define our file variables and default values, like votes and candidates.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Third Section&lt;/strong&gt; spans from Line 27–43 and only consists of one function, showCandidates, we simply use this to show our list of candidates once requested by the user.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Fourth Section&lt;/strong&gt; spans from Line 46–136 and consists of four functions which are in charge of actually accepting and validating users vote and showing the result to the user. The first two functions are the actual voting while the last two are for showing results. Here is how it works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a) castVote&lt;/strong&gt;(): It begins the voting process and also takes users vote. Once a user chooses to vote and this method is called for the first time through Line 218, it creates a tracker for that particular user in the server through Line 82, after it has performed a check to ascertain that there are candidates to be voted for(Line 81).&lt;/p&gt;

&lt;p&gt;It then returns a response with the list of candidates with their id to enable the user to know how to vote for their chosen candidate in their next chat, it also includes a way to cancel the voting process and remove the tracker from the user end by appending the unique value(0) which should be used by the user to opt-out of the voting process (Line 83 which calls list_of_candidate accepts showCandidates function as a parameter).&lt;/p&gt;

&lt;p&gt;When the user responds next with a chat, we then check by converting the chat value to a Number and check its value, if it's a 0, we know the user wants to cancel the voting process(Line 203), we then cancel the process and send a response to the user that we have. If the user rather sends any other value we then call &lt;strong&gt;castVote&lt;/strong&gt; with the required parameters(Line 207).&lt;/p&gt;

&lt;p&gt;When castVote is called and passed these values we then go to line 75 where we make sure the user hasn't voted before, then we proceed to Line 76 to recheck that the user has indeed begun the process of voting and lastly we proceed to confirm that there are actually candidates to be voted for in Line 77. After this, we call &lt;strong&gt;addVote&lt;/strong&gt; in Line 78 with the provided parameters.&lt;/p&gt;

&lt;p&gt;b) &lt;strong&gt;addVote&lt;/strong&gt;(): This function is charged with the actual reception of users vote. Firstly we check at Line 58 to make sure that the value supplied by the user actually is an id of a Candidate. We then proceed to add that users vote, remove them from the voting process and send back a successful response (Line 61-63).&lt;/p&gt;

&lt;p&gt;c) &lt;strong&gt;showResult()&lt;/strong&gt;: We use this function to show the result to users. Line 118–119 is simply used to validate and make sure that votes and candidates exist respectively. At line 121 we group all votes by the candidate. Then at Line 122, we format the response we get from Line 121 in such a way we can show the user the name of each candidate, the total votes they amassed and their percentage of votes. Also, we show a winner or draw where applicable(the formatResult function at Line 95 helps us with this formatting and result response.&lt;/p&gt;

&lt;p&gt;d)&lt;strong&gt;formatResponse&lt;/strong&gt;(): Like said above, found at Line 95, it simply gets the grouped votes by their candidates, then it returns the names of each candidate, their votes count and percentage of votes. It also checks for a draw or winner and returns this formatted result as its response.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Fifth Section&lt;/strong&gt; spans from Line 139–191 and consists of display and default message and a footer which we include for every response. &lt;strong&gt;showDefaultMessage&lt;/strong&gt;() is used at the beginning to show a list of actions that can be performed. &lt;strong&gt;showHelp&lt;/strong&gt;() *&lt;strong&gt;*shows the help menu whenever it's called while the **footer&lt;/strong&gt; includes an additional message to all response.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Sixth and Last Section&lt;/strong&gt; which spans from Line 191–243 is where we accept the post request made to the server, parse the body content, process the user input and send a response. Line 197 simply gives us the user phone number, this is the unique identifier for each user. We use the switch statements to get users response and call the corresponding function.&lt;/p&gt;

&lt;p&gt;That's basically what this file does, it serves as the engine of our chatbot.&lt;/p&gt;

&lt;p&gt;Next, let's add the utility.js file that would hold our helper files&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We have just 4 methods here that basically help us to perform various manipulations of data.

&lt;p&gt;We also include our responses.js file&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Now that we are done with the coding section, your project structure should look something like this:

&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AtiHvp9SGtQzO2Fjt2pDUlg.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AtiHvp9SGtQzO2Fjt2pDUlg.png" alt="Project Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then have a functional server, we would now proceed to create a webhook that would allow us to redirect requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Webhook
&lt;/h2&gt;

&lt;p&gt;This allows Twilio API to be able to send the request to our application endpoint. This is where ngrok.io.&lt;/p&gt;

&lt;p&gt;If you don't have &lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt;, proceed &lt;a href="https://ngrok.com/download" rel="noopener noreferrer"&gt;here&lt;/a&gt; to see how to get and set it up to run in your system. We are going to use the URL provided by ngrok as our webhook URL.&lt;/p&gt;

&lt;p&gt;But before we do that we need to start our server, let's open a terminal at the root of our project and run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This would spin up our server and expose it to a port. In our case, that port is 4000.&lt;/p&gt;

&lt;p&gt;Next, we open a different terminal and run&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 4000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should then see this on your terminal, Ngrok doing its job!&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ae58LnG_4YYFIGIsaPnIpPg.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Ae58LnG_4YYFIGIsaPnIpPg.png" alt="Port Forwarding with Ngrok"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Though not needed we could go to the Web Interface URL(&lt;a href="http://127.0.0.1:4040" rel="noopener noreferrer"&gt;http://127.0.0.1:4040&lt;/a&gt;) provided in the image to see requests as they are made to the endpoints:&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%2Fcdn-images-1.medium.com%2Fmax%2F2488%2F1%2A6npkjXJXfa4bJ9GmygQlmA.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%2Fcdn-images-1.medium.com%2Fmax%2F2488%2F1%2A6npkjXJXfa4bJ9GmygQlmA.png" alt="Request Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now update the webhook in Twilio to point to the exposed URL provided by Ngrok. This would redirect all messages from Twilio to our nodeJs server running locally on our system. Head over here and input the URL obtained from Ngrok and append it with /vote as this is our full endpoint. Then update the input field labelled “WHEN A MESSAGE COMES IN” with this value.&lt;/p&gt;

&lt;p&gt;For our case, we would input &lt;a href="http://9905d7076291.ngrok.io/vote" rel="noopener noreferrer"&gt;http://9905d7076291.ngrok.io/vote&lt;/a&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%2Fcdn-images-1.medium.com%2Fmax%2F2552%2F1%2ARUTF0M1q19YYvmJdb76f0w.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%2Fcdn-images-1.medium.com%2Fmax%2F2552%2F1%2ARUTF0M1q19YYvmJdb76f0w.png" alt="Twilio Sandbox Configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Now that we have set up our webhook, let’s test it out on WhatsApp. A Hi message responds with the default message we supplied in our code. We can see that working properly:&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKy4eqycF_lnfuGB_GtZJhg.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKy4eqycF_lnfuGB_GtZJhg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when we send 3 to the bot, we get polling results back, it works!:&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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aai3YH7IVqS_77Tf_OspMeg.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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aai3YH7IVqS_77Tf_OspMeg.png" alt="Shows Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;The Live demo can be found &lt;a href="https://www.youtube.com/watch?v=xls_7abY27I" rel="noopener noreferrer"&gt;here&lt;/a&gt;. I went further to add more features to the project, the complete project with admin functionality and features can be found &lt;a href="https://github.com/chyke007/e-voting" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;A major reason why I love this voting application is that it allows me to partake in a voting process without having to leave my best messaging platform.&lt;/p&gt;

&lt;p&gt;Technological advances have enabled us to live out our imaginations which we would have never thought possible in the previous century. I have just lived out one of mine! I can’t wait to see what you build!&lt;/p&gt;

</description>
      <category>twilio</category>
      <category>node</category>
      <category>bot</category>
      <category>whatsappbot</category>
    </item>
    <item>
      <title>How I Ace Technical Interviews — A Personal Guide</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Thu, 16 Mar 2023 14:04:34 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-i-ace-technical-interviews-a-personal-guide-18l1</link>
      <guid>https://dev.to/aws-builders/how-i-ace-technical-interviews-a-personal-guide-18l1</guid>
      <description>&lt;h2&gt;
  
  
  How I Ace Technical Interviews — A Personal Guide
&lt;/h2&gt;

&lt;p&gt;There is no single and accurate test for knowledge, however, every organization must prepare its own process to vet and hire talents. The outcome: &lt;em&gt;A series of rigorous, specialized, and challenging set of tests that evaluate your coding skills, communication skills, problem-solving abilities, and your personality in general; *this process has come to be known as a&lt;/em&gt;** Technical Interview.***&lt;/p&gt;

&lt;p&gt;Although this process( which entails both phone screening, online coding challenges, 1–1 coding interview) may seem challenging and scary, it's a lot easier when you know what to prepare for and how to go about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The interview is harder than the actual job!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is a Technical Interview?
&lt;/h2&gt;

&lt;p&gt;It happens to be an assessment of candidates' abilities by taking them through a series of exam-like stages instead of a single and straightforward test. This involves one or all coding challenges, assignments, phone calls.&lt;/p&gt;

&lt;p&gt;There is a common saying in software development that &lt;em&gt;the interview is harder than the actual job. *How far this saying has traveled goes to tell us how demanding some interview processes are&lt;/em&gt;.*&lt;/p&gt;

&lt;p&gt;The process is quite tasking and demanding for all levels of developers but happens to really affect the beginners due to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;their lack of adequate preparation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;their anxiety caused by a lack of experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;their inadequate problem-solving skills.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;their poor grasp of basic CS.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that we have gotten over the long definitions, let get to the fun part!&lt;/p&gt;

&lt;p&gt;Over the last year, I have undergone a series of Technical Interviews, in both Local, International, and Outsourcing Platforms. Hence, I would be sharing my take on each stage I encountered, tips on scaling through each stage, things to avoid, things to take out from the process, and a general overview of it all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stages of the Interview Process
&lt;/h2&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%2Fcdn-images-1.medium.com%2Fmax%2F10660%2F0%2ATRCtxcSLujUMaLXI" 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%2Fcdn-images-1.medium.com%2Fmax%2F10660%2F0%2ATRCtxcSLujUMaLXI" alt="Photo by [bruce mars](https://unsplash.com/@brucemars?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes! You have just received that mail from the recruiting team to inform you that your resume caught their attention and they would love to move ahead with you to the next stage: the Technical Interview stage. Thumbs Up!&lt;/p&gt;

&lt;p&gt;At this point adrenaline shots within your body and you are filled with excitement and then when it subsides you come to face another reality, the fear of what to expect in this new stage. Well, welcome to the club!&lt;/p&gt;

&lt;p&gt;Based on my experience these are the common stages the entire process takes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Phone Call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assignment/Timed Coding Challenge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1–1 Coding Challenge.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phone Call Stage
&lt;/h3&gt;

&lt;p&gt;This could take the shape of a phone call asking about your personality, a bit about your skill and expertise, experience, passion, and expectation.&lt;/p&gt;

&lt;p&gt;The key thing to focus on here however is the ability to show our enthusiasm, passion for tech, communication skills, knowledge about the company, and work approach(do you love working in a team, open to remote).&lt;/p&gt;

&lt;p&gt;The key takeaway from this stage is that at its end both parties would be better informed about each other, what the job entails, the skill set required, and experience levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assignment/Timed Coding Challenge Stage
&lt;/h3&gt;

&lt;p&gt;This stage could involve them sending a take-home assessment to be completed and submitted at a specific time or an invitation to a platform where a timed coding task would be assigned.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;**Assignment(Take Home) — **This usually occurs to test one's knowledge level and ascertain if the skill listed in a resume is actually valid and if one possesses the skills needed in the organization. A specific language or framework could be required. From my experience, the key things to be done here is to get a proper understanding of the questions before attempting to write a single line of code(to see the catch), use best practice to stand out(proper structure, DRY approach, clean code), code documentation (include a README.md file), writing of tests!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;**Timed Coding Challenge — **This usually occurs to test one’s CS fundamentals, ability to work under pressure(the timed environment on its own is pressure, lol). Before beginning, take time to understand the environment been used, the question’s edge cases, and what is required. On some occasions, a human interview may be at the other end to observe the process and make sure there are no irregularities.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1–1 Coding Challenge Stage
&lt;/h3&gt;

&lt;p&gt;Here, we are expected to solve some challenges that may build on the previous stage or not at all. The interview may ask why certain choices were made in the previous stage, hence it's good practice to do all stages ourselves without external help!&lt;/p&gt;

&lt;p&gt;A major mistake I have seen made by lots of developers is that they tend to not engage their interview adequately by not taking them through their thought process, asking questions for clarification. A friend of mine told me a story of his friend who was invited to a 30mins challenge and he spent more than half the time understanding the environment! He could simply have asked!&lt;/p&gt;

&lt;p&gt;Speak boldly and precisely, ask questions about the task before even starting, engage and communicate with the interviewer throughout this stage as we walk them through how we intend to solve the challenge, be open to feedback.&lt;/p&gt;

&lt;p&gt;Hence the key thing to focus on here is our collaborating skills, technical/coding skills, problem-solving skills. These are skills needed to be shown at this stage, keep that in mind!&lt;/p&gt;

&lt;h2&gt;
  
  
  General Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Do mock interviews.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practice algorithm challenges on sites like Hackerrank, Codewars, Codility, and their likes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send out more applications so as to become more familiar with the process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Study up on most CS fundamentals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Study more on best practices in your domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick a language and be an expert in it!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learn how to manage your time properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practice how to stay calm and also how to communicate effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review your previous interviews(if any) and learn from them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Believe in your abilities.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Things to avoid
&lt;/h2&gt;

&lt;p&gt;These are common mistakes I and some other developers made and which came back to haunt us:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Not engaging the interviewer; they are humans too you know.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not preparing adequately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not receiving feedback positively throughout the process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not thinking through before actually attempting to write codes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Off you go!
&lt;/h2&gt;

&lt;p&gt;With these tips, you are in a good shape to ace that technical interview and move on to the next stage.&lt;/p&gt;

&lt;p&gt;The world awaits you!&lt;/p&gt;

</description>
      <category>technicalinterview</category>
      <category>programming</category>
      <category>personaldevelopment</category>
      <category>career</category>
    </item>
    <item>
      <title>How laziness saved my life
</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Tue, 08 Dec 2020 23:29:48 +0000</pubDate>
      <link>https://dev.to/chyke007/how-laziness-saved-my-life-5a5m</link>
      <guid>https://dev.to/chyke007/how-laziness-saved-my-life-5a5m</guid>
      <description>&lt;p&gt;&lt;em&gt;A crash course on effective laziness.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I feel quite lazy to find the best intro to this piece, I’d just lazily get to the crux of the matter. The writing of this article even took a lazy approach from the title (which I got from a book I read five years ago and which best expresses my ideas), to the proofreading (which was done by my close friends), and down to the publication (lol) because I didn’t have much time and also because some were just beyond me.&lt;/p&gt;

&lt;p&gt;I remember attending an executive orientation by someone I’d refer to as brother, since then his instructions about managing time and getting things done have remained with me. Amongst other things he taught that day, the &lt;strong&gt;&lt;em&gt;power of delegation&lt;/em&gt;&lt;/strong&gt; stood out for me. People need to learn to work as a unit to get stuff done and learn to delegate various tasks to others. If there is anything I learnt so far in my little experience in leadership, it is that you don’t need to do all the work, rather you need to just learn the art of delegation and watch people do the tasks while you coordinate, thereby boosting their self-confidence and also getting adequate rest for your body (since you are no machine). Anyone who has ever tried this approach, would find that it pays to be &lt;strong&gt;LAZY&lt;/strong&gt;, because it gets the work done faster, saves energy and one could use the rest of the time to watch Iron man make that snap that sends the mighty Thanos packing.&lt;/p&gt;

&lt;p&gt;It is sad that we rather find ourselves in a generation where people are made to believe that working independently at all times, is a show of self-will, strength or other abilities. This, however, is only a partial truth and leads to unhealthy competition as well as low productivity. Due to this mind-set, hidden deep within people, they tend to feel ashamed and insecure whenever the need arises to seek help and this leads most often to a failure of some sort. Those who eventually do, do it as a last resort, after trying multiple obviously wrong options which could prove detrimental to their health, career, finances, spirituality, family etc. Strong-willed people suffer from this too and sometimes they get the required results, but in the long run they tend to make mistakes; except if they are as Malika, the Warrior Queen; some even go to the extreme by (consciously or unconsciously) seeing &lt;em&gt;everything as a competition&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I have learnt(and still learning) to stop competing with people but rather to learn from them and reduce the probability of failing and trying again when there is someone to guide. This underlying laziness has saved me strength for more important things.&lt;/p&gt;

&lt;p&gt;It has been said of successful people, that they focus on the important things while leaving the trivial issues to others through delegation and teamwork. This can be referred to as being smart but I choose to call it &lt;strong&gt;effective Laziness-Laziness with a purpose&lt;/strong&gt;. For instance, why would I take the struggle to understand a difficult topic when I have a friend that could explain it to me in minutes? Or why would I struggle to do something all over again when it has been done by someone else? &lt;em&gt;Like it is said in programming, if the wheel is not broken don’t fix it!!!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As a programmer I love doing things from scratch, this enables me to learn the fundamental technology and this has helped me in my career so far. To be honest, I have also learnt the hard way that not everything needs to follow this approach, some need you to save the time and resources it takes to start from scratch and just use a tool already built by another lazy programmer (which must have been duly tested by the community) to get the work done faster, better and up to date with industry standards, never reinventing the wheel since it is not broken!!!.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Finally, everything depends on your ability to know when to be Lazy about issues&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>lifehacks</category>
      <category>teamwork</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Display Build Status and Test Coverage Badges for a Laravel Project</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Tue, 08 Dec 2020 17:32:04 +0000</pubDate>
      <link>https://dev.to/chyke007/display-build-status-and-test-coverage-badges-for-a-laravel-project-jg9</link>
      <guid>https://dev.to/chyke007/display-build-status-and-test-coverage-badges-for-a-laravel-project-jg9</guid>
      <description>&lt;p&gt;In search for a new developer role, I found myself building various projects just to scale through multiple interviews. One in particular was a Laravel project that included a specific instruction to display both &lt;strong&gt;build status and code coverage report&lt;/strong&gt; as badges in my readme.md file.&lt;/p&gt;

&lt;p&gt;I searched for help online but couldn't find any that gave the full guide to solving this problem, most only provided solutions for build status while ignoring the code coverage aspect. I had to figure this out and time was running out.&lt;/p&gt;

&lt;p&gt;This below is what I intended to achieve and I would be showing how I accomplished 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%2Fmiro.medium.com%2Fmax%2F201%2F1%2Ak34Iuru8UwMWSDpR8P8R-g.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%2Fmiro.medium.com%2Fmax%2F201%2F1%2Ak34Iuru8UwMWSDpR8P8R-g.png" alt="badges"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup repo with Travis CI and Coveralls
&lt;/h1&gt;

&lt;p&gt;If you haven’t already, the first thing you need to do is to move over to Travis and login using your GitHub account. Once logged in hit the “Add New Repository” button to activate your repo. Repeat this procedure at Coveralls.io.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configure PHPUnit and Coveralls
&lt;/h1&gt;

&lt;p&gt;Luckily for us, Laravel comes shipped with PHPUnit. This tutorial assumes you have some tests written already. If not, it's as simple as checking out the Laravel docs for writing test.&lt;br&gt;
We're also going to install Coveralls, which we'll use to host the coverage report by simply require it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require php-coveralls/php-coveralls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or by adding the following line to the require block of your composer.json file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"php-coveralls/php-coveralls": "^1.1"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This would add it to our composer.json file as a dependency.&lt;/p&gt;
&lt;h1&gt;
  
  
  Create a .travis.yml and .coveralls.yml
&lt;/h1&gt;

&lt;p&gt;We would now proceed to create a Travis configuration file(.travis.yml) at the root of our Laravel project to get Travis CI set up. Also we would be creating a .coveralls.yml which would be used to set up the path to our clover.xml&lt;/p&gt;

&lt;p&gt;Here's what my .travis.yml looks like: I'm setting the language, the version of php, and telling it which additional script to run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php&lt;/span&gt;
&lt;span class="na"&gt;php&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;7.3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;7.4&lt;/span&gt;
&lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;

&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rm -rf composer.lock&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cp .env.example .env&lt;/span&gt;
&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mkdir -p build/logs&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vendor/bin/phpunit -c phpunit.xml&lt;/span&gt;
&lt;span class="na"&gt;after_success&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;travis_retry php vendor/bin/coveralls&lt;/span&gt;
  &lt;span class="c1"&gt;# or enable logging&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;travis_retry php vendor/bin/coveralls -v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what my .coveralls.yml looks like: I'm assuming your phpunit.xml saves its clover.xml at the build/logs path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;coverage_clover&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/logs/clover.xml&lt;/span&gt;
&lt;span class="na"&gt;json_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/logs/coveralls-upload.json&lt;/span&gt;
&lt;span class="na"&gt;service_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;travis-ci&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the benefit of doubt, this is how my phpunit.xml and .env.example files looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span class="na"&gt;backupGlobals=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;backupStaticAttributes=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;bootstrap=&lt;/span&gt;&lt;span class="s"&gt;"vendor/autoload.php"&lt;/span&gt;
         &lt;span class="na"&gt;colors=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertErrorsToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertNoticesToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;convertWarningsToExceptions=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
         &lt;span class="na"&gt;processIsolation=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
         &lt;span class="na"&gt;stopOnFailure=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Unit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;"Test.php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;./tests/Unit&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Feature"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;"Test.php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;./tests/Feature&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span class="na"&gt;processUncoveredFilesFromWhitelist=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;".php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;./app&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/whitelist&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logging&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;log&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"coverage-html"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"tests/coverage"&lt;/span&gt; &lt;span class="na"&gt;showUncoveredFiles=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;log&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"coverage-clover"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"build/logs/clover.xml"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/logging&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;php&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"APP_ENV"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"testing"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"DB_CONNECTION"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"sqlite"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"BCRYPT_ROUNDS"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"CACHE_DRIVER"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"array"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"MAIL_DRIVER"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"array"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"QUEUE_CONNECTION"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"sync"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"SESSION_DRIVER"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"array"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/php&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/phpunit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=sqlite
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=:memory:
DB_USERNAME=homestead
DB_PASSWORD=secret

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

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

&lt;/div&gt;



&lt;h1&gt;
  
  
  Deploy code and display badges
&lt;/h1&gt;

&lt;p&gt;Here's the code for both of the badges I used in my readme.md file. Both Travis and Coveralls will supply embed links for these.&lt;/p&gt;

&lt;p&gt;Travis CI Build Badge&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[![Build Status](https://travis-ci.com/chyke007/credible.svg?branch=master)](https://travis-ci.com/chyke007/credible)

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

&lt;/div&gt;



&lt;p&gt;Coveralls Code Coverage Badge&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[![Coverage Status](https://coveralls.io/repos/github/chyke007/credible/badge.svg?branch=master)](https://coveralls.io/github/chyke007/credible?branch=master)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now once we push our code to GitHub with this setup it should send the build off to Travis, and Travis should send the coverage off to Coveralls.&lt;/p&gt;

&lt;p&gt;That is all, in general it was an exciting adventure, hopefully this serves as a guide to someone, a guide I wish I had!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>testing</category>
      <category>github</category>
    </item>
    <item>
      <title>Build a surveillance system using Raspberry Pi, NodeJS and Pir sensor</title>
      <dc:creator>Nwachukwu Chibuike</dc:creator>
      <pubDate>Tue, 08 Dec 2020 14:44:43 +0000</pubDate>
      <link>https://dev.to/chyke007/build-a-surveillance-system-using-raspberry-pi-nodejs-and-pir-sensor-452o</link>
      <guid>https://dev.to/chyke007/build-a-surveillance-system-using-raspberry-pi-nodejs-and-pir-sensor-452o</guid>
      <description>&lt;p&gt;On February 2018 my interest in embedded systems began after reading couple of articles on the topic and discussing with some friends of mine that had an idea on it. That been the case nothing really caught my interest than when I saw that JavaScript, a language I was very familiar with, was also in the embedded space through NodeJs( Server side JavaScript).&lt;/p&gt;

&lt;p&gt;In the article I would be showing you how I used the Raspberry Pi 3, NodeJs, Pir sensor to create a monitoring system. This system depends on the internet to send notifications and hence can be regarded as an IoT system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer: In this article I am assuming you have already set up the NodeJS environment in the raspberry pi and have everything installed and set up ready to run. If not please check out tutorials on setting up the Raspberry Pi 3 and NodeJs&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Tools we would be needing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The following below are the tools, packages, services I used to carry out this project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Raspberry Pi 3: The Raspberry Pi is a series of small single board computer developed in the United Kingdom by the Raspberry Pi Foundation to promote teaching of basic computer science schools and in developing countries. I used it here as our mini computer system.&lt;/li&gt;
&lt;li&gt;Pir Motion Sensor: Pyroelectric (“Passive”) Infrared Sensors allows you to sense motion, almost always used to detect whether a human has moved in or out of the sensors range. I used it here to detect motion&lt;/li&gt;
&lt;li&gt;Nodemailer: A node package for sending mails, I used it to send mails&lt;/li&gt;
&lt;li&gt;onoff: A node package which has GPIO access and interrupt detection with Node.js, I used it here to interface with the Raspberry Pi GPIO pins.&lt;/li&gt;
&lt;li&gt;RGB Led Light: Used as a signal system here to show when motion has been detected. It consist of three colors red, green and blue.&lt;/li&gt;
&lt;li&gt;Breadboard: A breadboard is a solderless device for temporary prototype with electronics and test circuit designs. Most electronic components in electronic circuits can be interconnected by inserting their leads or terminals into the holes and then making connections through wires where appropriate. I used it here to connect some of my hardware.&lt;/li&gt;
&lt;li&gt;Jumper wires(Female to male and Female to Female): These are electronic wires I used to connect my hardware's.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Work time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Time to get our hands dirty!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setting up hardware to board&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Setting up the RGB Led Light: Insert the three output legs of the RGB Led Light to the breadboard. Then insert the female-to-male jumper wire(male end) to the breadboard parallel to each leg of the RGB, attach the opposite ends of these jumper wire(female end) to any GPIO pins in the Pi you would want to use, in this article we would be using 2,4,17.&lt;/li&gt;
&lt;li&gt;Setting up the PIR Sensor : The sensor should likely have three ends, one for power, one for ground and one for output . Depending on the one you purchase, see a guide online on how to connect it to the pi board. In this article we would be using the GPIO pin 27 for output.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setting up the mailer module&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First create a folder we would be working in and move into it, create a package.json file by running &lt;strong&gt;&lt;em&gt;npm init&lt;/em&gt;&lt;/strong&gt; and following the prompt, then install the node package by running this code:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This would add the nodemailer to the node modules directory as &lt;br&gt;
one of our dependencies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new file called mailer.js and open it in any text editor of your choice, we would be writing the mailing function needed in this file.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodemailer&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;transporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodemailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

   &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;

    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yourmail@yourmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="na"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;function&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;timerId&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="nx"&gt;timerId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;timerId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="mi"&gt;10000&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;mailOptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SMART SURVIELLANCE &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

   &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yourmail@yourmail.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

   &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[Pi Bot] Intruder Detected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mr/Mrs/Miss. Your name ,

   Someone is trying to steal your raspberry pi 3.

   At : &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;
   &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;

   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; 
    Love,
    Pi Bot&lt;/span&gt;&lt;span class="dl"&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="nx"&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;Sending an Email now..&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nx"&gt;transporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mailOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="kd"&gt;function&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="nx"&gt;info&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;error&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="nx"&gt;log&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="k"&gt;else&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="nx"&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;Message sent: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&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;p&gt;First and foremost we import the nodemailer package into our &lt;br&gt;
code(line 1), then we add our credentials using the nodemailer &lt;br&gt;
createTransport method(line 3–15).&lt;/p&gt;

&lt;p&gt;We then initialize a variable that is used to delay the execution of mail sending until after 10 seconds of motion detection occurrence, so as to prevent multiple mails been sent when motion is detected at close intervals(line 21–27).&lt;/p&gt;

&lt;p&gt;The next section simply uses a variable mailOptions to store the details of the mail to be sent(line 29–50), while the transporter.sendMail method proceeds to send the actual mail, we use a callback here to check if the message was sent or not and then show the corresponding message in the console(line 54–67).&lt;/p&gt;

&lt;p&gt;The module is then exported using the in built NodeJs exports method as sendEmail&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Making the system functional&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create an index.js file located in the same path as the mailer.js file created earlier. This file would be the default entry file for our NodeJs application. As usual I would be pasting the code and then proceed to explain&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Gpio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onoff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Gpio&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;LED1&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;Gpio&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out&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;LED2&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;Gpio&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out&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;LED3&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;Gpio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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;pir&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;Gpio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;in&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="s2"&gt;both&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;pir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&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="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="k"&gt;if&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="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;blinkInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blinkLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&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="nx"&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;Intruder detected&lt;/span&gt;&lt;span class="dl"&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="nx"&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;Pi Bot deployed successfully!&lt;/span&gt;&lt;span class="dl"&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="nx"&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;Guarding the raspberry pi 3...&lt;/span&gt;&lt;span class="dl"&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;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./mailer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endBlink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15000&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;endBlink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blinkInterval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;LED1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;LED1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unexport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;LED2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;LED2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unexport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;LED3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;LED3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unexport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//included when we are working with sensors&lt;/span&gt;
    &lt;span class="nx"&gt;pir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unexport&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;exit&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;blinkLED&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;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&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;LED1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readSync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&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;else&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;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&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;LED2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readSync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&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;else&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;LED3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readSync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;LED3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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;p&gt;Firstly we import the onoff package and then use the GPIO method(line 1). Then we assign the three output of the RGB light to three variables and also initialize a state variable that would be used to know the current color in the RGB Led Light been shown(line 2–5).&lt;/p&gt;

&lt;p&gt;We also assign the Pir motion sensor on the Raspberry Pi pin 27 to a variable(line 7). After which we write a pir.watch function that watches for false positive from the Pir motion sensor(line 9). If there is an error we exit from executing the code, if not, meaning a valid motion was detected, we proceed to call a function that blinks the RGB light at 250 milliseconds interval(line 11). This function simply uses the state variable to know the color of the led light currently showing and then shows the next color at the next interval.&lt;/p&gt;

&lt;p&gt;We also import the sendEmail module from our mailer.js file and call it (line 17), after which we stop the blinking light after 15 seconds, clean up the program and exit(line 19–34).&lt;/p&gt;

&lt;p&gt;And wolla!, we have built a very easy yet effective monitoring system by just writing a few lines of code, that goes to show the immense power of NodeJS when combined with the elegance of the Raspberry Pi 3.&lt;/p&gt;

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

&lt;p&gt;You can do all sorts of things with this setup . You can even &lt;a href="https://docs.clickatell.com/channels/one-api/one-api-reference/"&gt;receive an sms&lt;/a&gt; or have &lt;a href="https://www.twilio.com/"&gt;Twilio&lt;/a&gt; call you whenever the alarm is tripped off!&lt;/p&gt;

&lt;p&gt;Let me know what did with this setup and this amazing chip in the comments!&lt;/p&gt;

</description>
      <category>raspberrypi3</category>
      <category>node</category>
      <category>iot</category>
      <category>diy</category>
    </item>
  </channel>
</rss>
