<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Murewa Writes]]></title><description><![CDATA[Software Engineer |Technical Writer | IT Project Manager]]></description><link>https://blog.murewaashiru.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 22:59:32 GMT</lastBuildDate><atom:link href="https://blog.murewaashiru.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[DevRel in the World of Brain-Computer Interfaces]]></title><description><![CDATA[The realm of Brain-Computer Interfaces (BCIs) is rapidly evolving, promising to revolutionize human-computer interaction.
From medical applications like restoring mobility and communication to entertainment and cognitive enhancement, BCIs are poised ...]]></description><link>https://blog.murewaashiru.com/devrel-in-the-world-of-brain-computer-interfaces</link><guid isPermaLink="true">https://blog.murewaashiru.com/devrel-in-the-world-of-brain-computer-interfaces</guid><category><![CDATA[DevRel]]></category><category><![CDATA[neuralink]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Tue, 25 Mar 2025 18:57:11 GMT</pubDate><content:encoded><![CDATA[<p>The realm of Brain-Computer Interfaces (BCIs) is rapidly evolving, promising to revolutionize human-computer interaction.</p>
<p>From medical applications like restoring mobility and communication to entertainment and cognitive enhancement, BCIs are poised to disrupt multiple industries. This nascent field, fueled by advancements in neuroscience and AI, represents a significant growth area for the next decade.</p>
<h1 id="heading-introducing-neuralink"><strong>Introducing “Neuralink“</strong></h1>
<p>Neuralink, founded by Elon Musk, stands out due to its ambitious goals and aggressive approach.</p>
<p>Their focus on developing a high-bandwidth BCI capable of reading and writing neural signals has captured the world's attention. Neuralink's potential applications, from treating neurological disorders to enabling direct brain-to-brain communication, are both compelling and controversial. This high-profile nature, combined with the complex technical challenges involved, makes Neuralink a fascinating case study for DevRel.</p>
<h2 id="heading-why-neuralink">Why Neuralink?</h2>
<p>Because it’s the most known, and therefore the most likely to have a developer community built around it. The technical hurdles are large, and the need for a strong developer community to create useful applications is paramount.</p>
<h1 id="heading-first-steps-for-neuralink-devrel"><strong>First Steps for Neuralink DevRel</strong></h1>
<p>Building a developer ecosystem around Neuralink would require a multi-faceted approach, prioritizing education, collaboration, and ethical considerations. Here are the initial steps:</p>
<ul>
<li><p><strong>Establish a Robust Documentation and Education Platform:</strong></p>
<ul>
<li><p>Given the complexity of BCI technology, creating comprehensive documentation, tutorials, and sample code is crucial.</p>
</li>
<li><p>This platform should cater to diverse audiences, from neuroscientists and engineers to software developers and application designers.</p>
</li>
<li><p>Online courses and workshops would further democratize access to Neuralink's technology.</p>
</li>
</ul>
</li>
<li><p><strong>Foster a Research and Development Community:</strong></p>
<ul>
<li><p>Neuralink should actively engage with researchers and developers through grants, hackathons, and open-source initiatives.</p>
</li>
<li><p>Creating a platform for sharing research findings and code would accelerate innovation.  </p>
</li>
<li><p>This could be done through a dedicated developer portal on the company website.</p>
</li>
</ul>
</li>
<li><p><strong>Address Ethical and Safety Concerns:</strong></p>
<ul>
<li><p>Given the sensitive nature of BCI technology, building trust and transparency is paramount.</p>
</li>
<li><p>Neuralink should establish a clear ethical framework and engage with ethicists, policymakers, and the public to address potential risks and concerns.  </p>
</li>
<li><p>This includes open discussions about data privacy, security, and the potential for misuse.  </p>
</li>
</ul>
</li>
<li><p><strong>Create a Developer API and SDK:</strong></p>
<ul>
<li><p>To allow 3rd party developers to build applications, Neuralink must create a robust API and SDK.</p>
</li>
<li><p>This must be well documented, and supported.</p>
</li>
</ul>
</li>
<li><p><strong>Build a Community Forum:</strong></p>
<ul>
<li>A place where developers can ask questions, share code, and discuss Neuralink-related topics. This would be a place to build a community, and gain valuable feedback.</li>
</ul>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>By prioritizing education, collaboration, and ethical considerations, Neuralink can cultivate a thriving developer ecosystem that drives innovation and ensures the responsible development of BCI technology.</p>
]]></content:encoded></item><item><title><![CDATA[DevRel: A Beginner's View]]></title><description><![CDATA[If you’re into Technical Writing or a member of any tech community, you’ve probably heard of the buzzword “DevRel.” It’s strange and confusing how so many job roles have been introduced into the world during this information age, and even confusing t...]]></description><link>https://blog.murewaashiru.com/devrel-a-beginners-view</link><guid isPermaLink="true">https://blog.murewaashiru.com/devrel-a-beginners-view</guid><category><![CDATA[DevRel]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Mon, 17 Mar 2025 20:45:45 GMT</pubDate><content:encoded><![CDATA[<p>If you’re into Technical Writing or a member of any tech community, you’ve probably heard of the buzzword “DevRel.” It’s strange and confusing how so many job roles have been introduced into the world during this information age, and even confusing to know how to fit into such roles.</p>
<p>Today, we’ll dive into what DevRel is through the lens of a beginner DevRel (but an experienced software engineer).</p>
<h1 id="heading-what-is-devrel-and-what-does-it-entail">What is DevRel and what does it entail?</h1>
<p>DevRel, short for Developer Relations, is a strategic function within technology companies that focuses on building and nurturing relationships with developers. It's about creating a strong, supportive community around a company's products or services. They act as advocates for both the company and the developers. They strive to create a win-win situation where developers can build great things with the company's products, and the company can benefit from a thriving developer ecosystem.</p>
<h1 id="heading-core-responsibilities"><strong>Core Responsibilities:</strong></h1>
<h2 id="heading-community-building"><strong>Community Building:</strong></h2>
<ul>
<li><ul>
<li><p>Creating and managing online and offline communities of developers.</p>
<ul>
<li><p>Fostering a sense of belonging and encouraging interaction and collaboration.</p>
</li>
<li><p>Organizing meetups, conferences, workshops, and other events.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="heading-advocacy-and-education"><strong>Advocacy and Education:</strong></h2>
<ul>
<li><ul>
<li><p>Serving as a bridge between the company and the developer community.</p>
<ul>
<li><p>Educating developers about the company's products and technologies.</p>
</li>
<li><p>Creating content such as blog posts, tutorials, documentation, and videos.</p>
</li>
<li><p>Giving talks and presentations at conferences and events.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="heading-feedback-and-insights"><strong>Feedback and Insights:</strong></h2>
<ul>
<li><ul>
<li><p>Gathering feedback from developers about their experiences with the company's products.</p>
<ul>
<li><p>Relaying this feedback to the product and engineering teams to improve the products.</p>
</li>
<li><p>Acting as a voice of the developer within the company.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="heading-enabling-developer-success"><strong>Enabling Developer Success:</strong></h2>
<ul>
<li><ul>
<li><p>Providing support and resources to help developers succeed with the company's products.</p>
<ul>
<li><p>Creating sample code, libraries, and other tools.</p>
</li>
<li><p>Helping developers troubleshoot issues and find solutions.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="heading-building-brand-awareness"><strong>Building Brand Awareness:</strong></h2>
<ul>
<li><ul>
<li><p>Helping to build a positive brand image among developers.</p>
<ul>
<li><p>Showing that the company cares about the developer community.</p>
</li>
<li><p>Creating content that developers find valuable.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>Key Goals of DevRel:</strong></p>
<ul>
<li><p>Increase adoption of the company's products and technologies.</p>
</li>
<li><p>Build a strong and engaged developer community.</p>
</li>
<li><p>Improve developer satisfaction and loyalty.</p>
</li>
<li><p>Gather valuable feedback for product development.</p>
</li>
<li><p>Enhance the company's reputation among developers.</p>
</li>
</ul>
<h1 id="heading-salary-scale">Salary Scale</h1>
<p>DevRels can earn as low as $52,000 and up to $212,000 depending on several factors. Source: <a target="_blank" href="https://develocity.io/exploring-salaries-in-developer-relations/">Develocity.io</a></p>
<h1 id="heading-my-unique-opinions">My Unique Opinions</h1>
<ul>
<li><p>The role does not require software development experience but it is an added advantage. It can help understand issues better; thus better communication.</p>
</li>
<li><p>It is an easy entry into tech that does not necessarily require coding.</p>
</li>
<li><p>It requires strong communication skills as you become the middleman between the company and the software users.</p>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>"Ultimately, DevRel is about people. It's about recognizing the power of community, understanding the needs of developers, and building relationships based on trust and mutual respect.</p>
]]></content:encoded></item><item><title><![CDATA[Bug Hunting on SAW]]></title><description><![CDATA[Web scraping is an automatic method to obtain large amounts of data from websites. The data is largely unstructured and can be further refined.
In this article, we will be testing the desktop application Scrape Any Website as an exercise for the HNGi...]]></description><link>https://blog.murewaashiru.com/bug-hunting-on-saw</link><guid isPermaLink="true">https://blog.murewaashiru.com/bug-hunting-on-saw</guid><category><![CDATA[Testing]]></category><category><![CDATA[testing tool]]></category><category><![CDATA[testing tools]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Tue, 02 Jul 2024 21:52:48 GMT</pubDate><content:encoded><![CDATA[<p>Web scraping is an automatic method to obtain large amounts of data from websites. The data is largely unstructured and can be further refined.</p>
<p>In this article, we will be testing the desktop application Scrape Any Website as an exercise for the HNGi11 program.</p>
<h3 id="heading-learning-objectives">Learning Objectives</h3>
<p>At the end of this tutorial, you should be able to understand:</p>
<ul>
<li><p>Have an introductory understanding of the Scrape Any Website tool.</p>
</li>
<li><p>Some bugs observed on the platform</p>
</li>
</ul>
<h3 id="heading-dependencies">Dependencies</h3>
<ul>
<li><p>Download the tool via the website <a target="_blank" href="https://sawbinaries.s3.amazonaws.com/ScrapeAnyWebsite_1.1.15.0_x86.msix">Scrape Any Website</a> or Windows Store download page <a target="_blank" href="https://apps.microsoft.com/detail/9mzxn37vw0s2">Scrape Any Website</a></p>
</li>
<li><p>Documentation of the report (bugs) using Google Sheet.</p>
</li>
</ul>
<h3 id="heading-bug-report">Bug Report</h3>
<p>View the bug report via <a target="_blank" href="https://docs.google.com/spreadsheets/d/10jreyG0sm-jr6XRvd3eFzeCWa4nkMKGfpuLXsv1JSxw/edit?usp=sharing">Bug Report</a></p>
<h3 id="heading-bugs-observed">Bugs Observed</h3>
<p>The following bugs were observed.</p>
<ol>
<li>On creating a new Scrape Job Name, the textbox font colour (white) is the same as the background colour (white). The text is not visible.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719953084339/4eea4361-d907-4343-9f39-ce4f5fa42f0e.png" alt class="image--center mx-auto" /></p>
<p>Image 1.1- Adding a Scrape Job</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719953164945/552725a7-c0b1-49d1-b3e8-3ac9c29755f3.png" alt class="image--center mx-auto" /></p>
<p>Image 1.2- Adding a Scrape Job with text highlighted</p>
<ol start="2">
<li>URL Text Constraint not working</li>
</ol>
<p>The condition "x" must be a part of the URL failed as I was able to add the LinkedIn URL.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719954050696/59554127-b8d5-43e2-9f6b-36b28f6f1472.png" alt class="image--center mx-auto" /></p>
<p>Image 2.1- URLText Constraint not working</p>
<ol start="3">
<li>URL with text constraint scraped "unsuccessfully"</li>
</ol>
<p>Following issue 2, the LinkedIn website was scraped but no further information was provided.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719955122592/c643b04f-1992-4644-951f-5cee52130fbb.png" alt class="image--center mx-auto" /></p>
<p>Image 3.1- URL with text constraint scraped "unsuccessfully"</p>
<ol start="4">
<li>Application shutdown on upload of URLs from file</li>
</ol>
<p>In addition to no template provided, the application completely shut down on providing an Excel sheet containing URLs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719955179799/9476e9d6-4211-4eda-a40d-75a580e18139.png" alt class="image--center mx-auto" /></p>
<p>Image 4.1- Application shutdown on upload of URLs from file</p>
<ol start="5">
<li>URL took too long to add</li>
</ol>
<p>After restarting the application and trying to add a single URL, it seemed nothing worked. Closing the pop-up and clicking the "Save" button multiple times, the URL was finally saved.</p>
<p><img src alt class="image--center mx-auto" /></p>
<p>Image 5.1- URL took too long to add</p>
<ol start="6">
<li>No result from the scraping.</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Although this article was written in line with the requirement of the HNGi11 Testing track, I hope you have learnt about the ScrapeAnyWebsite tool and standard testing reporting template.</p>
]]></content:encoded></item><item><title><![CDATA[Creating a CRUD app with Java Spring Boot]]></title><description><![CDATA[Java is a multi-platform, object-oriented, and network-centric language. Spring Boot is an open-source Java-based framework used to create a microservice. It provides a good platform for Java developers to develop stand-alone and production-grade spr...]]></description><link>https://blog.murewaashiru.com/creating-a-crud-app-with-java-spring-boot</link><guid isPermaLink="true">https://blog.murewaashiru.com/creating-a-crud-app-with-java-spring-boot</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[lombok]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sat, 29 Jul 2023 22:22:55 GMT</pubDate><content:encoded><![CDATA[<p>Java is a multi-platform, object-oriented, and network-centric language. Spring Boot is an open-source Java-based framework used to create a microservice. It provides a good platform for Java developers to develop stand-alone and production-grade spring applications.</p>
<p>This tutorial aims to walk through building a Spring Boot Rest CRUD(Create-Read-Update-Delete) API using Java Spring Boot. REST APIs serve as a middleman between the backend server and the frontend/mobile application.</p>
<h3 id="heading-learning-objectives">Learning Objectives</h3>
<p>At the end of this tutorial, you should be able to understand and independently carry out the following:</p>
<ul>
<li><p>Initialize a new Spring Boot application with the relevant dependencies</p>
</li>
<li><p>Implement business logic</p>
</li>
<li><p>Work with test/mock data</p>
</li>
<li><p>Use Postman to test your application</p>
</li>
</ul>
<h3 id="heading-dependencies">Dependencies</h3>
<ul>
<li><p><a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html">Java Development Kit (JDK) 8</a> or higher</p>
</li>
<li><p>An IDE (e.g. IntelliJ, <a target="_blank" href="https://www.eclipse.org/">Eclipse</a>). I’ll be using IntelliJ</p>
</li>
<li><p>Terminal or cmd</p>
</li>
<li><p><a target="_blank" href="https://www.postman.com/downloads/">Postman</a></p>
</li>
</ul>
<h3 id="heading-major-headings">Major headings</h3>
<ul>
<li><p>Generate a New Spring Boot Gradle Project with Spring Initializer</p>
</li>
<li><p>Set up the project</p>
</li>
<li><p>Create the Movie model</p>
</li>
<li><p>Create the Movie service</p>
</li>
<li><p>Create the Movie controller and routes</p>
</li>
<li><p>Run and test the app using Postman</p>
</li>
</ul>
<h2 id="heading-generate-a-new-spring-boot-gradle-project-with-spring-initializer">Generate a New Spring Boot Gradle Project with Spring Initializer</h2>
<p>Spring Initializer is an easy way to get started with your spring boot application.</p>
<ul>
<li><p>Open up your browser and load https://start.spring.io/</p>
</li>
<li><p>Choose "Maven" as the project</p>
</li>
<li><p>Choose "Java" as the language</p>
</li>
<li><p>Add Spring Web and Lombok as dependencies</p>
</li>
<li><p>Choose the Java version you have installed on your system</p>
</li>
<li><p>Leave other configurations as they are</p>
</li>
<li><p>Click on the Generate button to download the project as a zipped file</p>
</li>
<li><p>Extract the zip file and open the project in an IDE</p>
</li>
<li><p>Sync the dependencies with Maven. Although, this might happen automatically.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690406518336/626693c0-c507-41db-b39b-ea73926473a0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-create-the-movie-model"><strong>Create the Movie Model</strong></h3>
<p>The data model is represented as Java classes and as database tables. The business logic of the system is done by the Java objects while the database provides permanent storage for the objects.</p>
<p>We will start by creating a <code>models</code> package in our root project package <code>com.example.demo</code>.</p>
<p>Within the <code>models</code> package created above, create a Java class with the name <code>Movie</code> with the fields as shown below.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Movie</span> </span>{
    <span class="hljs-keyword">private</span> Integer id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String description;
    <span class="hljs-keyword">private</span> String genre;
}
</code></pre>
<p>Although, the <code>@Data</code> annotation from Lombok encapsulates the creation of the constructor, getters &amp; setters, and the toString() method.</p>
<p>A <strong>constructor</strong> is a block of code that’s called when an instance of an object is created.</p>
<p><strong><em>Getters</em></strong> and <strong><em>setters</em></strong> are the class methods used to manipulate the data of the class fields. The getter is used to read or get the data of the class field whereas the setter is used to set the data of the class field to some variable.</p>
<p>The <strong><em>toString()</em></strong> is an in-built method in Java that returns the value given to it with the string format.</p>
<p>This is the full <em>Movie</em> class if you were to include the above methods.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.demo.models;
<span class="hljs-keyword">import</span> lombok.Data;

<span class="hljs-meta">@Data</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Movie</span> </span>{
    <span class="hljs-keyword">private</span> Integer id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String description;
    <span class="hljs-keyword">private</span> String genre;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Movie</span><span class="hljs-params">()</span> </span>{ }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Movie</span><span class="hljs-params">(Integer id, String name, String description, String genre)</span> </span>{
        <span class="hljs-keyword">this</span>.id = id;
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.description = description;
        <span class="hljs-keyword">this</span>.genre = genre;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> id;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(Integer id)</span> </span>{
        <span class="hljs-keyword">this</span>.id = id;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> name;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getDescription</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> description;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setDescription</span><span class="hljs-params">(String description)</span> </span>{
        <span class="hljs-keyword">this</span>.description = description;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getGenre</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> genre;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setGenre</span><span class="hljs-params">(String genre)</span> </span>{
        <span class="hljs-keyword">this</span>.genre = genre;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Movie{"</span> +
                <span class="hljs-string">"id="</span> + id +
                <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
                <span class="hljs-string">", description='"</span> + description + <span class="hljs-string">'\''</span> +
                <span class="hljs-string">", genre='"</span> + genre + <span class="hljs-string">'\''</span> +
                <span class="hljs-string">'}'</span>;
    }
}
</code></pre>
<h3 id="heading-create-the-movie-service"><strong>Create the Movie Service</strong></h3>
<p>A service contains an interface or abstract class that defines the functionalities it provides. We, however, won’t be creating an interface, we’ll go straight to define the functionalities.</p>
<p>In the root package of our application create a package with the name <code>services</code>. In the <code>services</code> package created above, create a called <code>MovieService</code>.</p>
<p>As opposed to setting up a database, we’ll be using dummy data which we’ll store in an ArrayList.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.demo.services;

<span class="hljs-keyword">import</span> com.example.demo.models.Movie;
<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MovieService</span> </span>{
    <span class="hljs-comment">//list of movies</span>
    <span class="hljs-keyword">private</span> List&lt;Movie&gt; movies;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> MovieService instance = <span class="hljs-keyword">null</span>;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> MovieService <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>{
        <span class="hljs-keyword">if</span>(instance == <span class="hljs-keyword">null</span>){
            instance = <span class="hljs-keyword">new</span> MovieService();
        }
        <span class="hljs-keyword">return</span> instance;
    }


    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MovieService</span><span class="hljs-params">()</span></span>{
        movies = <span class="hljs-keyword">new</span> ArrayList&lt;Movie&gt;();
        movies.add(<span class="hljs-keyword">new</span> Movie(<span class="hljs-number">1</span>, <span class="hljs-string">"Avengers: End game"</span>, <span class="hljs-string">"A team of super heroes try to restore the world after half its population was wiped off."</span>, <span class="hljs-string">"Science Fiction"</span>));
        movies.add(<span class="hljs-keyword">new</span> Movie(<span class="hljs-number">2</span>, <span class="hljs-string">"Mr &amp; Mrs Smith"</span>, <span class="hljs-string">"A couple paired to kill each other"</span>, <span class="hljs-string">"Action"</span>));
        movies.add(<span class="hljs-keyword">new</span> Movie(<span class="hljs-number">3</span>, <span class="hljs-string">"Black is King"</span>, <span class="hljs-string">"A musical movie compiled from songs from The Lion King Movie"</span>, <span class="hljs-string">"Motion Picture"</span>));
        movies.add(<span class="hljs-keyword">new</span> Movie(<span class="hljs-number">4</span>, <span class="hljs-string">"Reign"</span>, <span class="hljs-string">"The life of Mary, Queen of Scot"</span>, <span class="hljs-string">"History"</span>));
        movies.add(<span class="hljs-keyword">new</span> Movie(<span class="hljs-number">5</span>, <span class="hljs-string">"Enola Holmes"</span>, <span class="hljs-string">"Enola Holmes goes on a journey to find her missing mother"</span>, <span class="hljs-string">"Adventure"</span>));
    }

    <span class="hljs-comment">// return all Movies</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Movie&gt; <span class="hljs-title">fetchMovies</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> movies;
    }

    <span class="hljs-comment">// return Movie by id</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">getMovieById</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>{
        <span class="hljs-keyword">for</span>(Movie m: movies) {
            <span class="hljs-keyword">if</span>(m.getId() == id) {
                <span class="hljs-keyword">return</span> m;
            }
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    <span class="hljs-comment">// create Movie</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">createMovie</span><span class="hljs-params">(Integer id, String name, String description, String genre)</span> </span>{
        Movie newMovie = <span class="hljs-keyword">new</span> Movie(id, name, description, genre);
        movies.add(newMovie);
        <span class="hljs-keyword">return</span> newMovie;
    }

    <span class="hljs-comment">// update Movie</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">updateMovie</span><span class="hljs-params">(Integer id, String name, String description, String genre)</span> </span>{
        <span class="hljs-keyword">for</span>(Movie m: movies) {
            <span class="hljs-keyword">if</span>(m.getId() == id) {
                <span class="hljs-keyword">int</span> movieIndex = movies.indexOf(m);
                m.setName(name);
                m.setDescription(description);
                m.setGenre(genre);
                movies.set(movieIndex, m);
                <span class="hljs-keyword">return</span> m;
            }
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    <span class="hljs-comment">// delete movie by id</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span>{
        <span class="hljs-keyword">int</span> movieIndex = -<span class="hljs-number">1</span>;
        <span class="hljs-keyword">for</span>(Movie m: movies) {
            <span class="hljs-keyword">if</span>(m.getId() == id) {
                movieIndex = movies.indexOf(m);
                <span class="hljs-keyword">continue</span>;
            }
        }
        <span class="hljs-keyword">if</span>(movieIndex &gt; -<span class="hljs-number">1</span>){
            movies.remove(movieIndex);
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }
}
</code></pre>
<h3 id="heading-create-the-movie-controller"><strong>Create the Movie Controller</strong></h3>
<p>The controller is where the main business logic is implemented.</p>
<p>In the root package of our project create a package with the name <code>controllers</code>. In the <code>controllers</code> package we created above, create a Java class with the name <code>MovieController</code>.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.example.demo.controllers;

<span class="hljs-keyword">import</span> com.example.demo.models.Movie;
<span class="hljs-keyword">import</span> com.example.demo.services.MovieService;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;

<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.Map;

<span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("api/movies")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MovieController</span> </span>{
    MovieService movieService = MovieService.getInstance();

    <span class="hljs-meta">@GetMapping("")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Movie&gt; <span class="hljs-title">getMovie</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> movieService.fetchMovies();
    }

    <span class="hljs-meta">@GetMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">getMovieById</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> String id)</span></span>{
        <span class="hljs-keyword">int</span> movieId = Integer.parseInt(id);
        <span class="hljs-keyword">return</span> movieService.getMovieById(movieId);
    }

    <span class="hljs-meta">@PostMapping("")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> Map&lt;String, String&gt; body)</span></span>{
        <span class="hljs-keyword">int</span> noOfMovies = movieService.fetchMovies().size();
        <span class="hljs-keyword">int</span> movieId = noOfMovies + <span class="hljs-number">1</span>;
        String name = body.get(<span class="hljs-string">"name"</span>);
        String description = body.get(<span class="hljs-string">"description"</span>);
        String genre = body.get(<span class="hljs-string">"genre"</span>);
        <span class="hljs-keyword">return</span> movieService.createMovie(movieId, name, description, genre);
    }

    <span class="hljs-meta">@PutMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Movie <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> String id, <span class="hljs-meta">@RequestBody</span> Map&lt;String, String&gt; body)</span></span>{
        <span class="hljs-keyword">int</span> movieId = Integer.parseInt(id);
        String name = body.get(<span class="hljs-string">"name"</span>);
        String description = body.get(<span class="hljs-string">"description"</span>);
        String genre = body.get(<span class="hljs-string">"genre"</span>);
        <span class="hljs-keyword">return</span> movieService.updateMovie(movieId, name, description, genre);
    }

    <span class="hljs-meta">@DeleteMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> String id)</span></span>{
        <span class="hljs-keyword">int</span> movieId = Integer.parseInt(id);
        <span class="hljs-keyword">return</span> movieService.delete(movieId);
    }
}
</code></pre>
<p>All words prefixed with <strong><em>@</em></strong> are called <strong><em>Annotations</em></strong>. An annotation is a form of metadata that provides data about a program. In other words, annotations are used to provide <strong>supplemental</strong> information about a program.</p>
<ul>
<li><p>@<strong><em>RequestController</em></strong> indicates that the class can process HTTP requests.</p>
</li>
<li><p>@<strong><em>RequestMapping</em></strong>(“api/movies”) sets the base path/route for all request endpoints within the controller</p>
</li>
<li><p>@<strong><em>GetMapping</em></strong> indicates the method can process GET requests</p>
</li>
<li><p>@<strong><em>PostMapping</em></strong> indicates the method can process POST requests</p>
</li>
<li><p>@<strong><em>PutMapping</em></strong> indicates the method can process PUT requests</p>
</li>
<li><p>@<strong><em>DeleteMapping</em></strong> indicates the method can process DELETE requests</p>
</li>
</ul>
<h3 id="heading-run-and-test-the-app-using-postman"><strong>Run and test the app using Postman</strong></h3>
<p>Let’s run the application. Go to the <code>DemoApplication</code> class in the root folder and click on the play button to the left.</p>
<p>Launch Postman and let’s start testing.</p>
<p><strong>Get all movies</strong></p>
<p>Make a GET request to <a target="_blank" href="http://localhost:8080/api/movies">http://localhost:8080/api/movies</a> to return the array of all movies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690406925798/1697109e-1ee7-4b83-a0dd-85e90042707d.png" alt class="image--center mx-auto" /></p>
<p><strong>Create a new movie</strong></p>
<p>Make a POST request to <a target="_blank" href="http://localhost:8080/api/movies">http://localhost:8080/api/movies</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690406956068/482c36f3-992c-4a6d-9ee2-b1f08ab152d9.png" alt class="image--center mx-auto" /></p>
<p><strong>Get a movie by ID movie</strong></p>
<p>Make a GET request to <a target="_blank" href="http://localhost:8080/api/movies/%7Bid%7D">http://localhost:8080/api/movies/{id}</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690407027615/586ea880-1049-4446-a2dd-444c24b2d534.png" alt class="image--center mx-auto" /></p>
<p><strong>Update a movie by ID movie</strong></p>
<p>Make a PUT request to <a target="_blank" href="http://localhost:8080/api/movies/%7Bid%7D">http://localhost:8080/api/movies/{id}</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690407044060/9adc4900-b835-4033-a6b7-997f9bd963fe.png" alt class="image--center mx-auto" /></p>
<p><strong>Delete a movie by ID movie</strong></p>
<p>Make a PUT request to <a target="_blank" href="http://localhost:8080/api/movies/%7Bid%7D">http://localhost:8080/api/movies/{id}</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690407060353/ef8cc1b9-ed60-4c18-8aa5-a5fef76af17e.png" alt class="image--center mx-auto" /></p>
<p>That's a wrap. Go ahead and create your first Springboot application.</p>
<p>As an enhancement, you can connect to a database for data persistence.</p>
<h2 id="heading-resources"><strong>Resources</strong></h2>
<ul>
<li><p><a target="_blank" href="https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm">Spring Boot - Introduction</a></p>
</li>
<li><p><a target="_blank" href="https://www.geeksforgeeks.org/getter-and-setter-methods-in-dart/">Getter and Setter Methods in Dart</a></p>
</li>
<li><p><a target="_blank" href="https://www.section.io/engineering-education/spring-boot-crud-api/">How to create CRUD API using Spring Boot</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/javarevisited/getting-started-with-spring-boot-with-postgres-18f72612108c">Getting Started With Spring Boot With Postgres</a></p>
</li>
</ul>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Top Wireframe Tools for Websites & Mobile Apps]]></title><description><![CDATA[Going straight to coding without a ‘definite’ idea of what your app should look and feel like is very risky and can lead to unnecessary rework. It’s therefore necessary to plan a roadmap or process flow. This does not mean you have to have it all pla...]]></description><link>https://blog.murewaashiru.com/top-wireframe-tools-for-websites-mobile-apps</link><guid isPermaLink="true">https://blog.murewaashiru.com/top-wireframe-tools-for-websites-mobile-apps</guid><category><![CDATA[wireframes]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Thu, 20 Jul 2023 11:00:09 GMT</pubDate><content:encoded><![CDATA[<p>Going straight to coding without a ‘definite’ idea of what your app should look and feel like is very risky and can lead to unnecessary rework. It’s therefore necessary to plan a roadmap or process flow. This does not mean you have to have it all planned out at the start or it has to be top quality, a sketch will serve as a good starting point.</p>
<p>A wireframe is a skeletal blueprint of an application that establishes the flow of the application. It is a low-fidelity sketch that shows the main features of the application.</p>
<h3 id="heading-learning-objectives"><strong>Learning Objectives</strong></h3>
<p>At the end of this tutorial, you should be able to understand the following:</p>
<ul>
<li><p>Importance of wireframing</p>
</li>
<li><p>Various tools for wireframe</p>
</li>
<li><p>Pros and cons for each tool</p>
</li>
<li><p>The most comfortable use case for your application</p>
</li>
</ul>
<h3 id="heading-importance-of-wireframing"><strong>Importance of Wireframing</strong></h3>
<p>The pros of wireframing include the following:</p>
<ul>
<li><p>It brings clarity to the project in terms of client needs and primary focus.</p>
</li>
<li><p>It makes communication with teams easier.</p>
</li>
<li><p>It facilitates a better feedback process.</p>
</li>
<li><p>It minimizes rework.</p>
</li>
<li><p>It helps to identify problems early.</p>
</li>
</ul>
<h3 id="heading-wireframing-tools"><strong>Wireframing Tools</strong></h3>
<ol>
<li><p>Pen/Pencil and Paper</p>
</li>
<li><p>Figma</p>
</li>
<li><p>Pencil</p>
</li>
<li><p>Adobe XD</p>
</li>
<li><p>Bizagi Modeler</p>
</li>
</ol>
<h3 id="heading-penpencil-and-paper"><strong>Pen/Pencil and Paper</strong></h3>
<p>Not too big on using tech tools or very sporadic? No problem. Good old-fashion pen and paper can do the trick just as well.</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>It is easier and faster to use.</p>
</li>
<li><p>It has little to no cost implication.</p>
</li>
<li><p>It allows for early feedback from users.</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>It can be hard to interpret.</p>
</li>
<li><p>It is hard to review designs when users are geographically dispersed.</p>
</li>
<li><p>Constant erasing can distort the design.</p>
</li>
<li><p>Designs still have to be transferred to a digital tool</p>
</li>
</ul>
<h3 id="heading-figma">Figma</h3>
<p><a target="_blank" href="https://www.figma.com/">Figma</a> is a web-based graphics editing and user interface design app. It can be used for all kinds of graphic design work like wireframing websites, designing mobile app interfaces, prototyping designs, and much more.</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>It supports real-time collaboration between teams or individuals.</p>
</li>
<li><p>There are <a target="_blank" href="https://www.figma.com/file/GBCGqs11KNeUyPksQzEMw0hr/Wireframing/duplicate">wireframe templates</a> to start with.</p>
</li>
<li><p>It is easy to share designs.</p>
</li>
<li><p>It is cloud-based, as such, can be accessed from several devices without needing to download files.</p>
</li>
<li><p>It offers a free plan to users, with limited functionalities.</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>Although it has an offline version, users don’t have access to the full functionalities.</p>
</li>
<li><p>Real-time collaboration requires you to be online.</p>
</li>
<li><p>Poor version control. You have to be aware of the last edit made. </p>
</li>
</ul>
<p><strong>Learning Resources</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.figma.com/resources/learn-design/">Learn Design with Figma</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=tRpoI6vkqLs">UI Design Fundamentals Crash Course (YouTube)</a></p>
</li>
<li><p><a target="_blank" href="https://www.classcentral.com/course/ui-design-6890">Introduction to UI Design (Free Course)</a></p>
</li>
</ul>
<h3 id="heading-adobe-xd">Adobe XD</h3>
<p><a target="_blank" href="https://www.adobe.com/africa/products/xd.html">Adobe XD</a> is a vector-based experience design platform for wireframing, prototyping, interactive design, and hi-fidelity web/app design for individuals or teams.</p>
<p><strong>Pricing</strong></p>
<ul>
<li><p>7 days free trial.</p>
</li>
<li><p>US$11.49/mo for a single app.</p>
</li>
<li><p>US$60.94/mo for all (20+) apps.</p>
</li>
</ul>
<h3 id="heading-pros">Pros</h3>
<ul>
<li><p>It supports real-time collaboration between teams or individuals.</p>
</li>
<li><p>It supports animations.</p>
</li>
<li><p>It integrates with other Adobe products.</p>
</li>
<li><p>It is available on Windows and Mac OS.</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>The User Interface is not that attractive</p>
</li>
<li><p>It does not support many 3rd party plugins </p>
</li>
</ul>
<p><strong>Learning Resources</strong></p>
<ul>
<li><a target="_blank" href="https://www.vandelaydesign.com/free-adobe-xd-tutorials/">35 Free Adobe XD Tutorials for Learning UI/UX Designers</a></li>
</ul>
<h3 id="heading-pencil-evolus-pencil">Pencil (Evolus Pencil)</h3>
<p><a target="_blank" href="https://pencil.evolus.vn/">Pencil</a> is an open-source GUI prototyping tool that people can easily install and use to create mockups on popular desktop platforms.</p>
<p><strong>Pros</strong></p>
<ul>
<li><p>It is supported on all operating systems.</p>
</li>
<li><p>It is free.</p>
</li>
<li><p>It supports the drag and drop of elements.</p>
</li>
<li><p>It has a lot of UI elements categorized by device types.</p>
</li>
<li><p>It is integrated with OpenClipart.org to let users easily find clipart by keywords.</p>
</li>
<li><p>Although outdated, it has a Firefox extension.</p>
</li>
</ul>
<h3 id="heading-bizagi-modeler">Bizagi Modeler</h3>
<p><a target="_blank" href="https://www.bizagi.com/en/platform/modeler">Bizagi modeler</a> is a business process mapping software that enables organizations to create and document business processes in a central cloud repository to gain a better understanding of each step and identify process improvement opportunities to increase organizational efficiency.</p>
<p><strong>Pricing</strong></p>
<ul>
<li><p>Free for personal use.</p>
</li>
<li><p>USD$/mo for professionals.</p>
</li>
<li><p>USD$/mo/user for workgroups.</p>
</li>
<li><p>For enterprise, <a target="_blank" href="https://www.bizagi.com/en/contact-us">contact the team</a>.</p>
</li>
</ul>
<p><strong>Pros</strong></p>
<ul>
<li><p>It supports real-time collaboration between teams or individuals. </p>
</li>
<li><p>It is easy to use and user-friendly.</p>
</li>
<li><p>It supports Business Process Model and Notation (BPMN) notations.</p>
</li>
<li><p>It supports data visualization.</p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>The User Interface is not that attractive.</p>
</li>
<li><p>Unlike its competitors e.g LucidChart, it is not integrated with many 3rd party services (e.g. Jira, Google Drive, Github) for better collaboration. </p>
</li>
</ul>
<p><strong>Learning Resources</strong></p>
<ul>
<li><a target="_blank" href="https://www.bizagi.com/en/modeler-videos">Video tutorials</a></li>
</ul>
<p>Now that we’ve looked at just a few of the multiple tools (LucidChart, drawio, Microsoft Visio, and much more) that can be used, why don’t you go ahead and try them out and see what works for you.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://www.justinmind.com/blog/why-wireframing-your-interface/">Beginners’ guide to wireframing UIs: benefits &amp; best practices</a></li>
<li><a target="_blank" href="https://www.trustradius.com/products/adobe-xd/reviews?qs=pros-and-cons">Adobe XD</a></li>
<li><a target="_blank" href="https://www.getapp.com/it-management-software/a/lucidchart-online-diagramming-flowchart-and-drawing-software/compare/bizagi/">Lucidchart vs Bizagi Comparison</a></li>
</ul>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Getting started with MongoDB transactions using Node.js]]></title><description><![CDATA[The need to maintain database integrity cannot be overemphasized. One of the ways to ensure this is by performing ACID transactions; this simply means that actions that are meant to be completed as a 'whole' are either all completed or not completed ...]]></description><link>https://blog.murewaashiru.com/getting-started-with-mongodb-transactions-using-nodejs</link><guid isPermaLink="true">https://blog.murewaashiru.com/getting-started-with-mongodb-transactions-using-nodejs</guid><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Thu, 25 Nov 2021 00:00:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637793347803/UySaGjJLr.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The need to maintain database integrity cannot be overemphasized. One of the ways to ensure this is by performing <a target="_blank" href="https://en.wikipedia.org/wiki/ACID">ACID</a> transactions; this simply means that actions that are meant to be completed as a 'whole' are either all completed or not completed at all.</p>
<h2 id="heading-key-takeaways">Key takeaways</h2>
<p>By the end of this tutorial, the reader will be able to understand:</p>
<ul>
<li>What database transactions are</li>
<li>When to use database transactions</li>
<li>How to use MongoDB's database transaction</li>
</ul>
<h2 id="heading-dependencies">Dependencies</h2>
<ol>
<li>Node.js (version &gt;= 14.0)</li>
<li>MongoDB Atlas account</li>
<li>Code editor e.g. VSCode</li>
<li>Terminal or CMD</li>
<li>Postman</li>
</ol>
<h2 id="heading-the-concept-called-database-transaction">The concept called 'database transaction'</h2>
<p>A database transaction is a unit of work performed within a database management system against a database that you want to treat as "a whole." A transaction generally represents any change in a database. Transactions in a database environment have two main purposes:</p>
<ol>
<li>To keep a database consistent even in cases of system failure. When execution stop (either partially or completely, many operations upon a database remain uncompleted or unclear status.</li>
<li>To provide isolation between programs accessing a database concurrently.</li>
</ol>
<p>In a database management system, a transaction is a single unit of logic or work, sometimes made up of multiple operations. Any logical calculation done in a consistent model in a database is known as a transaction. One example is a transfer from one bank account to another: the complete transaction requires subtracting the amount to be transferred from one account and adding that same amount to the other.</p>
<p>A database transaction has the following properties, referred to 'ACID':</p>
<ol>
<li>Atomic: All the commands that make up the transaction are treated as a single unit or not treated at all.</li>
<li>Consistent: It must conform to existing constraints in the database.</li>
<li>Isolated: It must not affect other transactions.</li>
<li>Durable: It must get written to persistent storage.</li>
</ol>
<p>A classical example is transferring money from one bank account to another. Money is debited from the source account and then credited to the destination account. The operation has to be fully completed else there will be a loss to either or both parties.</p>
<h2 id="heading-database-transaction-in-mongodb">Database transaction in MongoDB</h2>
<p>MongoDB added support for multi-document ACID transactions in version 4.0 in 2018 and extended that support for distributed multi-document ACID transactions in version 4.2 in 2019.</p>
<p>MongoDB's document model allows related data to be stored together in a single document. However, there are cases where true multi-document, multi-collection MongoDB transactions are the best choice.</p>
<p>MongoDB transactions work similarly to transactions in other databases. To use a transaction, start a MongoDB session through a driver. Then, use that session to execute your group of database operations. You can run any of the CRUD (create, read, update, and delete) operations across multiple documents, multiple collections, and multiple shards.</p>
<p>We'll be creating a simple application that performs typical banking transactions. Let's get into it!</p>
<h3 id="heading-create-your-mongo-atlas-account">Create your Mongo Atlas Account</h3>
<p>Skip this if you're familiar with the subject.</p>
<ol>
<li>Sign up on <a target="_blank" href="https://www.mongodb.com/">MongoDB Atlas</a>.</li>
<li>Create a new project or use any existing project of your choice.</li>
<li>Create a database/cluster. Follow the prompt.</li>
</ol>
<p>You should see something similar to this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637708058837/HkryQmYDw.png" alt="Image2- Database cluster.PNG" /></p>
<p>Click on <strong>Cluster</strong> -&gt; <strong>Connect your application</strong>.</p>
<p>Copy the connection string and save it somewhere. It should look like this: <code>mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.abcde.mongodb.net/myFirstDatabase?retryWrites=true&amp;w=majority</code></p>
<p>Update <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code> with the credentials you created.</p>
<h3 id="heading-set-up-the-starter-code">Set up the starter code</h3>
<p>Let's start by creating a new folder in any directory of your choice.</p>
<pre><code>mkdir demo-wallet
cd demo-wallet
</code></pre><p>Let's set up our node app.</p>
<p>Run the command <code>npm init</code> and follow the prompt. You should have something like this in your package.json file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637707968573/ysNq875mX.png" alt="Image1- Package.json" /></p>
<p>Install the following packages</p>
<pre><code>npm install dotenv express mongoose uuid

npm install nodemon --save-dev
</code></pre><p>Update the start script in <code>package.json</code> with this code.</p>
<pre><code><span class="hljs-comment">//package.json</span>

  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index"</span>,
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>
  },
</code></pre><p>Create a new file called <code>.env</code> and update accordingly. Credentials which are confidential are included here.</p>
<pre><code><span class="hljs-comment">//.env</span>

DATABASE_URL = mongodb+srv:<span class="hljs-comment">//&lt;username&gt;:&lt;password&gt;@cluster0.abcde.mongodb.net/myFirstDatabase?retryWrites=true&amp;w=majority</span>
PORT = <span class="hljs-number">4000</span>
</code></pre><p>Create an entry point <code>index.js</code>. The application will run starting from this point.</p>
<pre><code><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
dotenv.config();

<span class="hljs-keyword">const</span> app = express();
app.use(express.json());

mongoose
  .connect(process.env.DATABASE_URL, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>
  })
  .then(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Successfully connected to MongoDB!'</span>);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Unable to connect to MongoDB'</span>);
  });

<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">4000</span>;

app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server listening on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre><p>Start the server with the command <code>npm run dev</code> or <code>nodemon index</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637708132313/ZJ0DlwjIX.png" alt="Image3- Server running.PNG" /></p>
<h3 id="heading-create-the-models">Create the models</h3>
<p>Our application will only have 2 collections: <strong>Wallets</strong> and <strong>Transactions</strong>. <strong>Wallets</strong> store the accounts of all users while <strong>Transactions</strong> store all transactions performed by the users.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709323285/OEU6iD5oL.png" alt="Image4-Database schema.png" /></p>
<p>There is a 1-to-Many relationship between <strong>Wallets</strong> and <strong>Transactions</strong>. This means that a wallet can perform multiple transactions and multiple transactions can be tied to a single wallet account. The username will serve as the immutable field identifying a wallet.</p>
<p>Create a new folder called <code>models</code> and create 2 files; <code>wallets.js</code> &amp; <code>transactions.js</code>.</p>
<pre><code><span class="hljs-comment">// wallets.js</span>
<span class="hljs-keyword">const</span> mongoose =<span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> walletSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
  {
    <span class="hljs-attr">username</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">immutable</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">balance</span>: {
        <span class="hljs-attr">type</span>: mongoose.Decimal128,
        <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">default</span>: <span class="hljs-number">0.00</span>
    },

  },
  { <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span> }
);

<span class="hljs-keyword">const</span> Wallets = mongoose.model(<span class="hljs-string">'Wallets'</span>, walletSchema);
<span class="hljs-built_in">module</span>.exports = Wallets;


<span class="hljs-comment">// transactions.js</span>
<span class="hljs-keyword">const</span> mongoose =<span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> transactionSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
  {
    <span class="hljs-attr">trnxType</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">enum</span>: [<span class="hljs-string">'CR'</span>, <span class="hljs-string">'DR'</span>]
    },
    <span class="hljs-attr">purpose</span>:{
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">enum</span> : [<span class="hljs-string">'deposit'</span>, <span class="hljs-string">'transfer'</span>, <span class="hljs-string">'reversal'</span>, <span class="hljs-string">'withdrawal'</span>],
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">amount</span>: {
      <span class="hljs-attr">type</span>: mongoose.Decimal128,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">default</span>: <span class="hljs-number">0.00</span>
    },
    <span class="hljs-attr">walletUsername</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">ref</span>: <span class="hljs-string">'Wallets'</span>
    },
    <span class="hljs-attr">reference</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-attr">balanceBefore</span>: {
      <span class="hljs-attr">type</span>: mongoose.Decimal128,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">balanceAfter</span>: {
      <span class="hljs-attr">type</span>: mongoose.Decimal128,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">summary</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-attr">trnxSummary</span>:{ <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> }
  },
  { <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span> }
);

<span class="hljs-keyword">const</span> Transactions = mongoose.model(<span class="hljs-string">'Transactions'</span>, transactionSchema);
<span class="hljs-built_in">module</span>.exports = Transactions;
</code></pre><p>Explaining the fields:</p>
<ul>
<li><strong>trnxType</strong> -&gt; This represents the type of transactions performed on a wallet; either a credit or a debit.</li>
<li><strong>purpose</strong> -&gt; What is the essence of the transaction? 'deposit', 'transfer', 'reversal', 'withdrawal' or 'reversal'</li>
<li><strong>amount</strong> -&gt; The transaction amount in decimal</li>
<li><strong>walletUsername</strong> -&gt; This is a foreign key that mapps to the <em>username</em> in the <em>Wallet</em> collection. It identifies the user to whom the transaction relates.</li>
<li><strong>reference</strong> -&gt; This represents an identifier to the database transactions; both debit and credit leg of the transaction.</li>
<li><strong>balanceBefore</strong> -&gt; This represents the wallet balance before the transaction occurred.</li>
<li><strong>balanceAfter</strong> -&gt; This represents the wallet balance after the transaction occurred.</li>
<li><strong>summary</strong> -&gt; This represents the message from the sender on the details or purpose of the transaction.</li>
<li><strong>trnxSummary</strong> -&gt; This represents a summary of the entire transaction. It can include the reference, purpose, sender username, etc as is deemed fit.</li>
</ul>
<h3 id="heading-the-business-logic-wallets">The business logic; Wallets</h3>
<p>For any new user onboarded, a wallet is created with a balance of 0 and no transaction. Create 2 new folders called <code>controllers</code> and <code>routes</code>. Create a <code>wallets.js</code> file in each folder.</p>
<p>We'll create Create operation on the <em>Wallets</em> collections.</p>
<pre><code><span class="hljs-comment">// controllers/wallets.js</span>
<span class="hljs-keyword">const</span> Wallets = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/wallets'</span>);

<span class="hljs-keyword">const</span> createWallet = <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">try</span>{
        <span class="hljs-keyword">const</span> {username}= req.body;

        <span class="hljs-keyword">const</span> walletExists = <span class="hljs-keyword">await</span> Wallets.findOne({username});
        <span class="hljs-keyword">if</span> (walletExists){
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">409</span>).json({
                <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">message</span>: <span class="hljs-string">'Wallet already exists'</span>,
            })
        }

        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> Wallets.create({username});
        <span class="hljs-built_in">console</span>.log(result)
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).json({
            <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">message</span>: <span class="hljs-string">'Wallets created successfully'</span>,
            <span class="hljs-attr">data</span>: result
        })
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">message</span>: <span class="hljs-string">`Unable to create wallet. Please try again. \n Error: <span class="hljs-subst">${err}</span>`</span>
        })
    }
}

<span class="hljs-built_in">module</span>.exports = { createWallet };
</code></pre><p>Now we add the routes so we can test the URLs in Postman</p>
<pre><code><span class="hljs-comment">// routes/wallets.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-keyword">const</span> Wallets = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/wallets'</span>);

router.post(<span class="hljs-string">'/'</span>, Wallets.createWallet);

<span class="hljs-built_in">module</span>.exports = router;
</code></pre><p>Update <code>index.js</code> to include these routes</p>
<pre><code><span class="hljs-keyword">const</span> walletRoutes = <span class="hljs-built_in">require</span>( <span class="hljs-string">'./routes/wallets'</span>);
app.use(<span class="hljs-string">'/api/wallets'</span>, walletRoutes);
</code></pre><p>Let's test the application and create 2 wallets.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709581028/JE624bVQ4.png" alt="Image5-Create wallets.PNG" /></p>
<h3 id="heading-the-business-logic-transactions">The business logic; Transactions</h3>
<p>According to the accounting principle of double-entry, for every debit entry, there must be a corresponding credit entry.</p>
<p>Create a folder called <code>utils</code> and a file called <code>transactions.js</code></p>
<p>The 2 methods are <code>debitAccount</code> which will debit the sender and <code>creditAccount</code> which will credit the received. We begin by searching if the user exists; the sender in <code>debitAccount()</code> and the receiver in <code>creditAccount</code>. The amount to be transferred must be greated than the wallet balance of the sender. Once all checks pass, the wallet balance will be updated and the transactions recorded.</p>
<pre><code><span class="hljs-comment">/**
 * <span class="hljs-doctag">@param <span class="hljs-type">{decimal128}</span> <span class="hljs-variable">amount</span></span> - in decimal
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">username</span></span>
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">purpose</span></span>
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">reference</span></span>
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">summary</span></span>
 * <span class="hljs-doctag">@param <span class="hljs-type">{String}</span> <span class="hljs-variable">trnxSummary</span></span>
 * <span class="hljs-doctag">@returns <span class="hljs-type">{object}</span> </span>custom response
*/</span>
</code></pre><pre><code><span class="hljs-comment">// utils/transactions.js</span>
<span class="hljs-keyword">const</span> Wallets = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/wallets'</span>);
<span class="hljs-keyword">const</span> Transactions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/transactions'</span>);

<span class="hljs-keyword">const</span> creditAccount = <span class="hljs-keyword">async</span> ({amount, username, purpose, reference, summary, trnxSummary, session}) =&gt; {
  <span class="hljs-keyword">const</span> wallet = <span class="hljs-keyword">await</span> Wallets.findOne({username});
  <span class="hljs-keyword">if</span> (!wallet) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">statusCode</span>:<span class="hljs-number">404</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">`User <span class="hljs-subst">${username}</span> doesn\'t exist`</span>
    }
  };

  <span class="hljs-keyword">const</span> updatedWallet = <span class="hljs-keyword">await</span> Wallets.findOneAndUpdate({username}, { <span class="hljs-attr">$inc</span>: { <span class="hljs-attr">balance</span>: amount } }, {session});

  <span class="hljs-keyword">const</span> transaction = <span class="hljs-keyword">await</span> Transactions.create([{
    <span class="hljs-attr">trnxType</span>: <span class="hljs-string">'CR'</span>,
    purpose,
    amount,
    username,
    reference,
    <span class="hljs-attr">balanceBefore</span>: <span class="hljs-built_in">Number</span>(wallet.balance),
    <span class="hljs-attr">balanceAfter</span>: <span class="hljs-built_in">Number</span>(wallet.balance) + <span class="hljs-built_in">Number</span>(amount),
    summary,
    trnxSummary
  }], {session});

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Credit successful`</span>)
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">statusCode</span>:<span class="hljs-number">201</span>,
    <span class="hljs-attr">message</span>: <span class="hljs-string">'Credit successful'</span>,
    <span class="hljs-attr">data</span>: {updatedWallet, transaction}
  }
}

<span class="hljs-keyword">const</span> debitAccount = <span class="hljs-keyword">async</span> ({amount, username, purpose, reference, summary, trnxSummary, session}) =&gt; {
  <span class="hljs-keyword">const</span> wallet = <span class="hljs-keyword">await</span> Wallets.findOne({username});
  <span class="hljs-keyword">if</span> (!wallet) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">statusCode</span>:<span class="hljs-number">404</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">`User <span class="hljs-subst">${username}</span> doesn\'t exist`</span>
    }
  };

  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Number</span>(wallet.balance) &lt; amount) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">statusCode</span>:<span class="hljs-number">400</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">`User <span class="hljs-subst">${username}</span> has insufficient balance`</span>
    }
  }

  <span class="hljs-keyword">const</span> updatedWallet = <span class="hljs-keyword">await</span> Wallets.findOneAndUpdate({username}, { <span class="hljs-attr">$inc</span>: { <span class="hljs-attr">balance</span>: -amount } }, {session});
  <span class="hljs-keyword">const</span> transaction = <span class="hljs-keyword">await</span> Transactions.create([{
    <span class="hljs-attr">trnxType</span>: <span class="hljs-string">'DR'</span>,
    purpose,
    amount,
    username,
    reference,
    <span class="hljs-attr">balanceBefore</span>: <span class="hljs-built_in">Number</span>(wallet.balance),
    <span class="hljs-attr">balanceAfter</span>: <span class="hljs-built_in">Number</span>(wallet.balance) - <span class="hljs-built_in">Number</span>(amount),
    summary,
    trnxSummary
  }], {session});

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Debit successful`</span>);
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">statusCode</span>:<span class="hljs-number">201</span>,
    <span class="hljs-attr">message</span>: <span class="hljs-string">'Debit successful'</span>,
    <span class="hljs-attr">data</span>: {updatedWallet, transaction}
  }
}

<span class="hljs-built_in">module</span>.exports = {
    creditAccount, debitAccount
};
</code></pre><p>Create a new file in the <code>controllers</code> folder called <code>transactions.js</code>. The main business logic will be executed here.</p>
<p>If the debit is successful but the credit is not successful is not, the entire transaction will be rolled back; the sender is credited with the amount.</p>
<p>For any error that occurs, all successful operations will be rolled back.</p>
<pre><code><span class="hljs-comment">// controllers/transactions.js</span>
<span class="hljs-keyword">const</span> Transactions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/transactions'</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
<span class="hljs-keyword">const</span> { v4 } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'uuid'</span>);
<span class="hljs-keyword">const</span> { creditAccount, debitAccount } = <span class="hljs-built_in">require</span>( <span class="hljs-string">'../utils/transactions'</span>);

<span class="hljs-keyword">const</span> transfer = <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> session = <span class="hljs-keyword">await</span> mongoose.startSession();
    session.startTransaction()
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { toUsername, fromUsername, amount, summary} = req.body;
        <span class="hljs-keyword">const</span> reference = v4();
        <span class="hljs-keyword">if</span> (!toUsername &amp;&amp; !fromUsername &amp;&amp; !amount &amp;&amp; !summary) {
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({
                <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
                <span class="hljs-attr">message</span>: <span class="hljs-string">'Please provide the following details: toUsername, fromUsername, amount, summary'</span>
            })
        }

      <span class="hljs-keyword">const</span> transferResult = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
        debitAccount(
          {amount, <span class="hljs-attr">username</span>:fromUsername, <span class="hljs-attr">purpose</span>:<span class="hljs-string">"transfer"</span>, reference, summary,
          <span class="hljs-attr">trnxSummary</span>: <span class="hljs-string">`TRFR TO: <span class="hljs-subst">${toUsername}</span>. TRNX REF:<span class="hljs-subst">${reference}</span> `</span>, session}),
        creditAccount(
          {amount, <span class="hljs-attr">username</span>:toUsername, <span class="hljs-attr">purpose</span>:<span class="hljs-string">"transfer"</span>, reference, summary,
          <span class="hljs-attr">trnxSummary</span>:<span class="hljs-string">`TRFR FROM: <span class="hljs-subst">${fromUsername}</span>. TRNX REF:<span class="hljs-subst">${reference}</span> `</span>, session})
      ]);

      <span class="hljs-keyword">const</span> failedTxns = transferResult.filter(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> result.status !== <span class="hljs-literal">true</span>);
      <span class="hljs-keyword">if</span> (failedTxns.length) {
        <span class="hljs-keyword">const</span> errors = failedTxns.map(<span class="hljs-function"><span class="hljs-params">a</span> =&gt;</span> a.message);
        <span class="hljs-keyword">await</span> session.abortTransaction();
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({
            <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">message</span>: errors
        })
      }

      <span class="hljs-keyword">await</span> session.commitTransaction();
      session.endSession();

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).json({
        <span class="hljs-attr">status</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">message</span>: <span class="hljs-string">'Transfer successful'</span>
    })
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">await</span> session.abortTransaction();
        session.endSession();

        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
            <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">message</span>: <span class="hljs-string">`Unable to find perform transfer. Please try again. \n Error: <span class="hljs-subst">${err}</span>`</span>
        })
    }
}

<span class="hljs-built_in">module</span>.exports = { transfer };
</code></pre><p>A reference is required to identify this unit of transaction. We use <code>uuid</code> to create this unique identifier.</p>
<p><code>const session = await mongoose.startSession(); session.startTransaction()</code> is used to initialize a database transaction.</p>
<p><code>const transferResult = await Promise.all([...])</code> takes <code>debitAccount()</code> and <code>creditAccount()</code> as input promises and returns a single Promise that resolves to an array of the results.</p>
<p>When either or both methods return with an error, the errors have to be displayed to the user and the transaction aborted. The <code>transferResult</code> is filtered based on the <code>status</code> returned from the helper methods. There is an error the status is <code>false</code>. The error(s) is(are) extracted and stored in <code>errors</code> and returned to the user. The session is aborted and all operations rolled back.</p>
<p>If there are no errors, we commit the transaction, end the session and return a success response to the user.</p>
<p>In the <code>catch</code> block, the transaction is aborted and the session ended. Network failure is a reason the catch block will be executed. All transactions performed will be rolled back.</p>
<p>Let's create the routes and update the <code>index.js</code> file with it</p>
<pre><code><span class="hljs-comment">// routes/transactions.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-keyword">const</span> Transactions = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/transactions'</span>);

router.post(<span class="hljs-string">'/transfer'</span>, Transactions.transfer);

<span class="hljs-built_in">module</span>.exports = router;


<span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">const</span> transactionRoutes = <span class="hljs-built_in">require</span>( <span class="hljs-string">'./routes/transactions'</span>);
app.use(<span class="hljs-string">'/api/transactions'</span>, transactionRoutes);
</code></pre><h3 id="heading-test-the-application">Test the application</h3>
<p>Right now, all transactions will fail because the wallet balances are 0. Head over to MongoDB and manually update the <code>balance</code> of a wallet. This wallet will act as the sender.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709605490/PNJhVCCuK.png" alt="Image6-MongoDB Wallet Collection.PNG" /></p>
<p>Back to Postman. Let's test with a sender who exists and a recipient who doesn't exist. We expect to debit the sender and then try to credit the receiver but since the receiver doesn't exist, the debit on the sender is reversed. The balances of the 2 users should be as before the transaction is performed and the <em>Transactions</em> collection should be empty.</p>
<p>Check the console, you will see the <code>Debit successful</code> message. The debit leg was successful but the credit leg was not. The debit was reversed and the operation was aborted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709633123/gagaunWpz.png" alt="Image7-Transfer Transaction.PNG" /></p>
<p>Let's try again with users who exist.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709644667/oP3eJxg6M.png" alt="Image8-Transfer Transaction2.PNG" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637709682679/GIV2gbemK.png" alt="Image9-MongoDB Transaction Collection.PNG" /></p>
<p>Now that you've learnt the basics, go ahead and try other transactions like reversals, withdrawals, deposits or other use cases.</p>
<h3 id="heading-nosql-databases-that-support-acid-transactions">NoSQL databases that support ACID transactions</h3>
<p>MongoDB is not the only NoSQL database that supports ACID transactions. RavenDB, FaunaDB and FoundationDB are ACID compliant.</p>
<h3 id="heading-references">References</h3>
<ul>
<li><a target="_blank" href="https://www.mongodb.com/basics/acid-transactions">What are ACID Transactions?</a></li>
<li><a target="_blank" href="https://ravendb.net/articles/acid-transactions-in-nosql-ravendb-vs-mongodb">ACID Transactions in NoSQL? RavenDB vs MongoDB</a></li>
<li><a target="_blank" href="https://www.mongodb.com/developer/quickstart/node-transactions/">How to Use MongoDB Transactions in Node.js</a></li>
</ul>
<p><a href="https://www.buymeacoffee.com/murewaashiru" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" /></a></p>
]]></content:encoded></item><item><title><![CDATA[Hackathons/Programs to watch out for in Q4, 2021]]></title><description><![CDATA[This quarter is on a good start in the tech community with a lot of hackathons and programs happening globally.
African App Launchpad AAL Cup 2021
IBM is collaborating with Information Technology Industry Development Authority (ITIDA) in its 3rd edit...]]></description><link>https://blog.murewaashiru.com/hackathonsprograms-to-watch-out-for-in-q4-2021</link><guid isPermaLink="true">https://blog.murewaashiru.com/hackathonsprograms-to-watch-out-for-in-q4-2021</guid><category><![CDATA[hackathon]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Tue, 05 Oct 2021 23:17:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633475657472/hylhi8pNj.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This quarter is on a good start in the tech community with a lot of hackathons and programs happening globally.</p>
<h2 id="african-app-launchpad-aal-cup-2021">African App Launchpad AAL Cup 2021</h2>
<p>IBM is collaborating with Information Technology Industry Development Authority (ITIDA) in its 3rd edition of the African Application Launchpad Cup (AAL Cup 2021) — to launch the "Africa for Creative Games and Digital Applications" competition. The competition aims to up-skill 10,000 African youth and support 100 startups in the field of applications and game development. Participants will get the chance to leverage IBM SMEs and train using the IBM Digital - Nation Africa platform. Selected winners will enjoy IBM mentorship opportunities and get the chance to deploy their solutions on IBM Cloud using the worldwide program "Startup with IBM".</p>
<p><strong>Eligible African Countries-</strong> Egypt, Algeria, Angola, Cameroon, Chad, Comoros, Côte d'Ivoire, Democratic Republic of the Congo, Ghana, Libya, Madagascar, Malawi, Mauritania, Namibia, Niger, Rwanda, Senegal, South Africa, The Gambia, Nigeria, Togo and Uganda.</p>
<p>Read more about the program <a target="_blank" href="http://techleaders.eg/aal/competition2021/">here</a></p>
<h2 id="au-digital-and-innovation-fellowship">AU Digital and Innovation Fellowship</h2>
<p>The fellowship program seeks highly competent tech innovators within the African continent to organs within the African Union Headquarters and organs as ‘resident fellows’ to understand the system within those organs; identify challenges within the system and propose solutions to these challenges.
The fellows will be expected to co-create and build innovative tailor-made products and processes that improve the delivery of the African Union’s mandate especially in the context of good governance and citizens engagement. Additionally, the program will seek to facilitate conditions for building the internal capacity of the host African Union organs in the long term.</p>
<p>Read more about the program <a target="_blank" href="https://auinnovationfellowship.com/">Here</a></p>
<h2 id="hacktoberfest">Hacktoberfest</h2>
<p>Hacktoberfest is a month-long celebration of open source software run by DigitalOcean. During the month of October, open-source software enthusiasts, beginners, and the developer community participate by contributing to open-source projects. It is open to everyone.</p>
<p>Read more about the program <a target="_blank" href="https://hacktoberfest.digitalocean.com/">here</a></p>
<p>Additional Resource- <a target="_blank" href="https://ayushirawat.com/beginners-guide-to-hacktoberfest-2021">Beginner's guide to Hacktoberfest 2021</a></p>
<h2 id="bridge-to-masschallenge-nigeria-2021">Bridge To MassChallenge Nigeria 2021</h2>
<p>Bridge to MassChallenge Nigeria is a national startup competition in partnership with the National Information Technology Development Agency that identifies and accelerates the top startups in Nigeria while connecting them to the MassChallenge global network. The program is focused on supporting early-stage startups across all industries that are based in Nigeria and interested in growing their business in the Nigerian market. </p>
<p>Read more about the program <a target="_blank" href="https://apply.masschallenge.org/-temporary-slug-195bbb91-3f42-4b90-b2b1-a1712dbc0c33?hs_preview=FrbYBroP-49904863060">here</a></p>
<h2 id="sca-web-monetized-hackathon">SCA Web Monetized Hackathon</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/SheCodeAfrica/status/1442764487656984578">https://twitter.com/SheCodeAfrica/status/1442764487656984578</a></div>
<p>As part of SheCodeAfrica's 5th Anniversary, Coil is sponsoring an Interledger and Web Monetization learning program. The hackathon is only open for female techies (SCA Community Members):</p>
<ul>
<li>Designers, Developers, Designers, Product Managers, and every other role</li>
<li>People looking to explore new ideas, build new skills and learn about Interledger and Web Monetization</li>
<li>Anyone who wants to learn about new advancements in open payments</li>
</ul>
<p>Join the SheCodeAfrica community via this <a target="_blank" href="bit.ly/scaslacksignup">link</a> to get started.</p>
<p>Read more about the program <a target="_blank" href="https://apply.africahacks.com/challenge/SheCodeAfrica_Web_Monetization_Challenge">here</a></p>
<h2 id="the-afriex-virtual-cryptoweb3-hackathon">The Afriex virtual crypto/web3 Hackathon</h2>
<p>The Afriex crypto/web3 hackathon is aimed at African developers to promote blockchain development on the continent By bringing together innovative minds, <a target="_blank" href="https://afriexapp.com/">Afriex</a> aims to build an enabling environment for blockchain developers on the continent. The event will last for 4 days and the Winning Team gets a grand prize of $1000 in crypto and a job offer or a chance to continue the project. (Form closes:6th October 2021.)</p>
<p>Read more about the program <a target="_blank" href="https://afriexapp.com/">here</a></p>
<p>Registration form- <a target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSdjJbK-1hn6LzfrnoMwnWgiV6La3W_9Gf-0BGIpgfYD4YZlhQ/viewform">Here</a></p>
<h2 id="mercury-hackathon-2021-all-about-nfts">Mercury Hackathon 2021: All about NFTs</h2>
<p>At the Mercury Hackathon 2021, we believe that the sky’s the limit in the world of blockchain and non-fungible tokens (NFTs). Join us on this 6-week online hackathon supported by Filecoin, IPFS &amp; Flow that brings together some of the most talented creators around the world to innovate and redefine boundaries. </p>
<p>With up to USD $120,000 worth of FIL &amp; FLOW tokens to be given out and 14 prize categories, participants can choose to build and develop projects spanning between NFTs and decentralized storage services. Wish to experience web3 storage, Estuary, Slate, or NFTstorage and beyond? Strap on, suit up &amp; let's get building.</p>
<p>Read more about the program <a target="_blank" href="https://ahack.link/AMBiolubisi">here</a></p>
<h2 id="red-brick-pre-accelerator-program">Red Brick Pre-accelerator Program</h2>
<p>This is a 6-week 100% online program targeted at start-up founders.</p>
<p>The different premade modules of our online program will help you to validate your idea, find your customer and support your team growth. You have access to high-quality content &amp; tools and will be in direct contact with experienced mentors and coaches. </p>
<p>Read more about the program <a target="_blank" href="https://redbrick.fi/programs/pre-accelerator-program/">here</a></p>
<h2 id="techondemand-hackthon-fsi-fintech-challenge">TechonDemand Hackthon (FSI Fintech Challenge)</h2>
<p>A Physical &amp; Virtual Hackathon Event to address the dominance of cash
transactions, manual processes, and access to financial services among retailers,
micro, small and medium enterprises (MSMEs) as well as individuals in
suburban parts of Nigeria including university communities and their environs.</p>
<p>Read more about the hackathon <a target="_blank" href="https://fsi.ng/innovation-challenge/1/techondemand">here</a></p>
<h2 id="pytorch-annual-hackathon-2021">PyTorch Annual Hackathon 2021</h2>
<p>The PyTorch Annual Hackathon is back in 2021 with all-new opportunities for you to get started or continue learning about PyTorch. Join the community to build innovative and impactful models, applications, and other projects that use AI responsibly.</p>
<p>What to Build: Build a project using PyTorch in one of the three categories: </p>
<ul>
<li>PyTorch Responsible AI Development Tools &amp; Libraries</li>
<li>Web and Mobile Applications powered by PyTorch</li>
<li>PyTorch Developer Tools &amp; Libraries</li>
</ul>
<p>Read more about the hackathon <a target="_blank" href="https://pytorch2021.devpost.com/?ref_feature=challenge&amp;ref_medium=homepage-recommended-hackathons">here</a></p>
<h2 id="aws-graviton-hackathon">AWS Graviton Hackathon</h2>
<p>Build or migrate an application to Amazon EC2 instances powered by Arm-based AWS Graviton2 processors for a chance to win $10,000 cash and a trip to re:Invent 2021.</p>
<p>AWS Graviton processors are custom built by Amazon Web Services using 64-bit Arm Neoverse cores to deliver the best price-performance for your cloud workloads running in Amazon EC2. AWS Graviton2 are the latest generation Arm-based processors that power a range of general-purpose, compute-optimized, and memory-optimized EC2 instances</p>
<p>Read more about the hackathon <a target="_blank" href="https://awsgraviton.devpost.com/?ref_feature=challenge&amp;ref_medium=homepage-recommended-hackathons">here</a></p>
<h2 id="shellai-hackathon-for-sustainable-and-affordable-energy">Shell.ai Hackathon for Sustainable and Affordable Energy</h2>
<p>Tackling climate change is an urgent challenge. Shell is transforming to become a net-zero emissions energy business by 2050, in step with society and our customers. We are exploring new opportunities to provide more low-carbon energy such as biofuels, hydrogen, charging for electric vehicles and electricity generated by solar and wind power. To achieve this, we are working collaboratively on unproven, early-stage ideas with the potential to impact the future of energy.</p>
<p>Help us harness the power of the sun and win monetary awards or funding for your project!</p>
<p>Read more about the hackathon <a target="_blank" href="https://www.hackerearth.com/challenges/competitive/shell-ai-hackathon-2021/">here</a></p>
<blockquote>
<p>Cover image <a target="_blank" href="https://unsplash.com/photos/p6YWrjhmjhM">Unsplah</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Stress: The inevitable]]></title><description><![CDATA[Stress is an inevitable part of life- whether going to work, school or just staying at home. It takes energy to get things done but there's only so much we can do before it's all zapped out. It's important to realize when one's stress level is gettin...]]></description><link>https://blog.murewaashiru.com/stress-the-inevitable</link><guid isPermaLink="true">https://blog.murewaashiru.com/stress-the-inevitable</guid><category><![CDATA[General Advice]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Wed, 12 May 2021 15:06:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1620759384559/4iVvZ4bqo.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Stress is an inevitable part of life- whether going to work, school or just staying at home. It takes energy to get things done but there's only so much we can do before it's all zapped out. It's important to realize when one's stress level is getting high and manage it.</p>
<p>That being established, let's take a deeper look into the subject.</p>
<h2 id="what-is-stress">What is stress?</h2>
<blockquote>
<p>A state of mental or emotional strain or tension resulting from adverse or demanding circumstances.</p>
<p>Physiological disturbance or damage caused to an organism by adverse circumstances.</p>
<p>(Oxford dictionary)</p>
</blockquote>
<h2 id="what-causes-stress">What causes stress?</h2>
<ol>
<li><strong>Money:</strong>  A popular saying goes, "If a man will not work, he shall not eat." Money is essential to survive. It's how we can afford certain pleasures of life or otherwise. It, however, is never enough because human needs are insatiable. Not having enough money to take care of essential needs is one of the major cause of stress around the world.</li>
<li><strong>Being under a lot of pressure or work overload: </strong> Having too much work is known to cause stress. It's common for companies or employers to overload their staff with a lot of work in a bid to "reduce cost and optimize profit." This might work for a little while but the resulting effect is a reduction in efficiency or staff or high staff turnover.</li>
<li>Facing discrimination or harassment at work</li>
<li><strong>Changes in the external environment: </strong> This can be explained using <a target="_blank" href="https://www.professionalacademy.com/blogs-and-advice/marketing-theories---pestel-analysis">PESTEL Analysis</a>. Changes outside your control have effects on activities you are involved in and cause favourable or unfavourable impact. </li>
<li>Underlying medical conditions</li>
<li><strong>Traumatic event, such as a natural disaster, pandemic, theft or rape:</strong> The COVID-19 pandemic is a typical example. It stressed a lot of individuals and companies. Questions about survival, the long-term impact on lives, companies, the economy, socio-economic environment and other areas were raised.</li>
<li><strong>Unrealistic expectations: </strong> No one is perfect. If you expect perfection at all times, you are bound to feel stressed as it is an impossible feat.</li>
<li>Big changes</li>
<li>Social discrimination</li>
</ol>
<h2 id="impact-of-stress">Impact of Stress</h2>
<ol>
<li>Constant fatigue</li>
<li>Depression</li>
<li>Medical conditions e.g. stroke, high blood pressure</li>
<li>Difficulty in sleeping</li>
<li>Unhappiness</li>
<li>Use of hard drugs or other illegal substances</li>
<li>Weight gain or loss</li>
</ol>
<h2 id="how-to-deal-with-stress">How to deal with Stress</h2>
<p>A few of the ways to destress are:</p>
<ol>
<li>Acknowledge that it is real and inevitable.</li>
<li>Speaking about what stresses you to friends, family or even a therapist.</li>
<li>Exercise and eat well.</li>
<li>Don't take on too much work. Delegate when you can.</li>
<li>Don't overthink. Some things are beyond your control.</li>
<li>Create a work-life balance strategy</li>
</ol>
<p>Managing your stress can make a real difference to your health, both physical and mental health. It's therefore imperative to be conscious about the causes of stress that we face and act on them.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://www.mind.org.uk/information-support/types-of-mental-health-problems/stress/what-is-stress/">Stress</a></li>
<li><a target="_blank" href="https://www.singlecare.com/blog/news/stress-statistics/">Stress statistics 2021: How common is stress and who’s most affected?</a></li>
<li>Cover Image- <a target="_blank" href="https://unsplash.com/photos/44D6S-5jDJQ">Unsplash</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Designing the Backend System of an Agritech App]]></title><description><![CDATA[With over 206 million people living in Nigeria (Source: Nigeria Population (2021) - Worldometer), it is evident that food is one of the most critical factors in the sustenance of its people and economy. Over the years, the country has noticed a decre...]]></description><link>https://blog.murewaashiru.com/designing-the-backend-system-of-an-agritech-app</link><guid isPermaLink="true">https://blog.murewaashiru.com/designing-the-backend-system-of-an-agritech-app</guid><category><![CDATA[System Architecture]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Mon, 22 Feb 2021 11:03:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613940818451/mYAWAD-6_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>With over 206 million people living in Nigeria (Source: <a target="_blank" href="https://www.worldometers.info/world-population/nigeria-population/">Nigeria Population (2021) - Worldometer</a>), it is evident that food is one of the most critical factors in the sustenance of its people and economy. Over the years, the country has noticed a decrease in the rate of food production and an increase in the rate of food importation. This is primarily due to an increase in the cost of local production and a shift of focus to Crude Oil as the major source of revenue since its discovery.</p>
<p>Although the Nigerian government, in recent years, has placed restrictions on the importation of certain kinds of food, local farmers are still in stiff competition to meet up with the demands and taste of the Nigerian people.</p>
<p>In November 2020, a team of 4 (myself included) decided to address the concern around agriculture in the SauceCode Hackathon. You can read the UI/UX case study for this project <a target="_blank" href="https://imanueljnr152.medium.com/designing-an-agricultural-loan-and-investment-app-a-ui-ux-case-study-fdad409eba2b">here</a>.</p>
<p><strong>Note: </strong> I will be using the words <em>investment</em> and <em>capital</em> interchangeably.</p>
<h2 id="problem">Problem</h2>
<p>The inability of farmers to easily access funds for their capital-intensive business which threatens its sustainability.</p>
<h2 id="solution">Solution</h2>
<p><strong>AgroFarm</strong> is a platform that connects farmers and customers together for the purpose of raising interest-bearing capital for farmers. This interest (or return on investment) will be shared between the service providers and the investors (customers) at an agreed rate.</p>
<h2 id="timeline">Timeline</h2>
<p>4 weeks</p>
<h2 id="tools-and-technologies">Tools and Technologies</h2>
<ul>
<li>Node.js/Express</li>
<li>PostgreSQL as database</li>
<li>Sequelize ORM</li>
<li><a target="_blank" href="https://dbdiagram.io/">Dbdiagram.io</a> for database schema design</li>
<li>Paystack for payment processing</li>
<li>Heroku for hosting</li>
<li>Cloudinary for image storing</li>
<li>Postman for API documentation</li>
</ul>
<h2 id="database-design-process">Database design process</h2>
<p>After scoping out the basic features, I began to design the database using Dbdiagram.io.
But before then, I asked myself some questions.</p>
<ul>
<li>Who are the users? Can they be divided into categories? </li>
<li>Are there similar properties all users should possess? What distinct properties should each category of user possess?</li>
<li>What information are farmers required to submit when making requests for capital?</li>
<li>Can a farmer have multiple ongoing investments?</li>
<li>Who determines the return on this capital? How will this be split?</li>
<li>Who can approve a request for capital? Is there any form of pre-approval and what qualifies a farmer for that?</li>
<li>When can customers see the investment requests and make payment?</li>
<li>What platform will be used to process payment? How do they process payment? Where will the payments from customers be received and payments to farmers be made from? Will the processing fee be passed to customers? Do they support recurrent payments?</li>
<li>What information about transactions will be recorded and at what point (initiating, or confirming success)?</li>
</ul>
<p>In answering these questions, I came up with the schema as seen in Fig 1 below; creating tables and fields before creating the relationships between tables.
I decided to use a relational (SQL) database (PostgreSQL) to create standardization, avoid duplication and data integrity, to mention a few. (You may argue that MongoDB provides for the following but NoSQL databases, in general, serves a purpose quite different from SQL databases).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613991643406/iZgU1B-vH.png" alt="AgroFarm DB Schema.png" />
<em>Fig 1: Database schema</em></p>
<h2 id="user-flow">User flow</h2>
<p>Users are categorized into 3- Customers, Farmers and Service provider.</p>
<p><strong>Service Provider</strong> refers to the company providing the platform, and by extension, its staff. It is the middleman between the customers and farmers, liaising with both sides to ensure ease of use and smooth operations on the app. It can also approve or reject investment requests from farmers.</p>
<p><strong>Farmers</strong> are the users who can make request for investment for their businesses.</p>
<p><strong>Customers</strong> are the users who invest in approved and available farm businesses.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613941081031/gE-OGjn53.png" alt="Farmer Flowchart.png" />
<em>Fig 2: User flow for farmers</em></p>
<h2 id="tough-times">Tough times</h2>
<p>This project was my first attempt at building an agritech solution. While thinking about the architecture, I had to think about what exactly was my expectation was concerning</p>
<ul>
<li>Wallet-enabled or not</li>
<li>Saving customer's card details to make recurrent payments, if needed</li>
<li>Accounting entries</li>
<li>Whether or not to use a micro-service architecture, even though I was the only backend developer.</li>
</ul>
<p>With the help of my mentor who works in the fintech sector, I was able to scope out what I wanted to achieve.</p>
<h2 id="lessons-learnt">Lessons Learnt</h2>
<p>1) No one starts a project without an objective. The design thinking (solution architecting) phase is key because it helps to:</p>
<ul>
<li>break down the overall objective into product features and work items.</li>
<li>identify resources (people, technology, time) needed.</li>
<li>identify the cost-benefit of the project.</li>
<li>save time.</li>
</ul>
<p>2) I learnt how to integrate into a payment processor. Read my article about integrating multiple payment processors <a target="_blank" href="https://blog.murewaashiru.com/payment-service-integration-200-countries-covered">here</a>.</p>
<p>3) Ask for help when you're stuck. If I didn't reach out to people I knew had solutions to the challenges I had, it would've taken a much longer time to break the phase of the implementation that needed it.</p>
<p>4) A challenge makes you better. My team ranked top 20 in the hackathon and I'm glad I decided to opt-in. I'm looking forward to more challenges and wins in the near future.</p>
<p><strong>Image credits</strong></p>
<p>Cover image and Fig 2 by <a target="_blank" href="https://imanueljnr152.medium.com/">Emmanuel Okononfua</a></p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[I like JavaScript, so should you! Here's why]]></title><description><![CDATA[The battle of the programming languages is one that has been on for many years and I perceive it will not end. In considering one's preferred programming language, one must have explored other languages, considered their area of interest (machine lea...]]></description><link>https://blog.murewaashiru.com/i-like-javascript-so-should-you-heres-why</link><guid isPermaLink="true">https://blog.murewaashiru.com/i-like-javascript-so-should-you-heres-why</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Mon, 25 Jan 2021 15:31:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1611588858675/T3QNgb8L5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The battle of the programming languages is one that has been on for many years and I perceive it will not end. In considering one's preferred programming language, one must have explored other languages, considered their area of interest (machine learning, mobile/web development, etc), scalability, maintainability, performance, target platform and many other factors. </p>
<p>JavaScript is my preferred programming language. In this article, I'll highlight a few of the reasons for my decision.</p>
<h2 id="easy-to-learn">Easy to learn</h2>
<p>JavaScript is easy to pick up and has a natural feel to it. Being a higher-level language, it abstracts away most of the complex details of the machine so you can focus on learning how to program. 
You can also start coding with JavaScript straight from your browser, before proceeding to set up any development environment to perform more complex activities.</p>
<h2 id="wide-span-of-use">Wide-span of use</h2>
<p>Originally, JavaScript could only be run on web browsers. However, due to its popularity and the need to reduce the number of languages/tools developers need to learn to accomplish a task, the need to expand its area of application became very eminent. JavaScript can now be used in areas such as IoT, frontend, desktop, backend, mobile, machine learning and game app development.</p>
<h2 id="dynamic-typed">Dynamic Typed</h2>
<p>Unlike its static-type counterparts (e.g. Java, C#), JavaScript does not demand you declare data types before using the variables. It is smart enough to deduce them and execute commands at runtime. This flexibility can pose several (security) threats which can, however, be managed using best practices and packages that address such concerns e.g. <a target="_blank" href="https://www.npmjs.com/package/joi">Joi</a> for Node.js.</p>
<h2 id="community-and-resources">Community and resources</h2>
<p>Due to its popularity, there are vast communities and resources available targeting beginner to expert level developers. In my opinion, there are more tech conferences that speak on JavaScript as a language or its libraries/frameworks than any other language.</p>
<h2 id="async-processing">Async processing</h2>
<p>JavaScript handles requests asynchronously. That means it does not wait for returns on a request before receiving another request. Instead, it logs the requests and delivers the response based on the execution time of each request (a request that takes a shorter time will be processed and returned faster than a request that takes a longer time).</p>
<h2 id="evolution-and-innovation">Evolution and innovation</h2>
<p>JavaScript frameworks, libraries and packages are released much more frequently than any other language. This is mainly driven by the open-source community which anyone can be a part of.</p>
<h2 id="resources-to-get-started">Resources to get started</h2>
<ul>
<li><a target="_blank" href="https://blog.rahulism.co/the-ultimate-and-free-javascript-resources">The ultimate and free JavaScript resources</a></li>
<li><a target="_blank" href="https://codelifefitness.hashnode.dev/list-of-my-favorite-javascript-resources">List of my favorite JavaScript resources🚀</a></li>
<li><a target="_blank" href="https://hashnode.com/post/ultimate-javascript-resources-that-every-programmer-should-know-cjwj5ikxg000o7ys1ar5pnqni">Ultimate JavaScript Resources That Every Programmer Should Know!!</a></li>
</ul>
<h2 id="closing-remarks">Closing remarks</h2>
<p>If you don't know JavaScript, what are you waiting for? Go ahead and explore the resources above. Good luck!</p>
<p>Despite supporting JavaScript, I believe it is important should consider the purpose and requirements of a project before deciding a language to use.</p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Journey in Tech: Tough times don't last, tough people do]]></title><description><![CDATA[The world looks at the people in tech as the solution providers. What they don't really understand are the efforts and challenges faced to rise to that status. I'll be sharing some of my challenges in this article and how I delt with them.
Low-qualit...]]></description><link>https://blog.murewaashiru.com/journey-in-tech-tough-times-dont-last-tough-people-do</link><guid isPermaLink="true">https://blog.murewaashiru.com/journey-in-tech-tough-times-dont-last-tough-people-do</guid><category><![CDATA[General Advice]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Wed, 06 Jan 2021 19:06:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1609960057860/ML5rbvVEH.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The world looks at the people in tech as the <em>solution providers</em>. What they don't really understand are the efforts and challenges faced to rise to that status. I'll be sharing some of my challenges in this article and how I delt with them.</p>
<h2 id="low-quality-laptop">Low-quality laptop</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609952667646/BliugJhzA.jpeg" alt="Dell Laptop.jpg" />
I used this laptop while in university; I was very annoyed and irritated when I received it during the 3rd semester. It had a 40GB hard disk size, 1GB RAM, the processor, battery life, speed and just about everything was awful. After a while, I got over it. I decided to use the laptop to its maximum capacity. Every semester, I would uninstall the IDE for the previous language learned to give room to install a new one and replace the battery every year. I still don't understand how Visual Studio survived on it. </p>
<p>Despite the hell I faced with this laptop, my programming and general academic activities were not distorted. Sure, it hindered progress because it couldn't handle some things I wanted to explore deeply, I made the best use of what I had and came out with good grades. (Read more about this <a target="_blank" href="https://www.linkedin.com/posts/activity-6438732967413055488-p96w">here</a>).</p>
<p>Fast-forwarding to months after graduation, I got a better laptop because the one in the picture suddenly shutdown (You don't understand the joy that struck me when it happened). Now I look back and wonder how I survived with that crapy old Dell. But it taught me patience and perseverance. I can't go back to that laptop though.</p>
<p><strong>Lessons:</strong></p>
<ol>
<li>The output of anything is more dependent on the person behind the machine than the machine itself.</li>
</ol>
<h2 id="imposter-syndrome">Imposter Syndrome</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1609954766767/eIIktua-0.jpeg" alt="Black girl.jpg" />
(Source: <a target="_blank" href="https://images.unsplash.com/photo-1524223476077-443396c2cecf?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=750&amp;q=80">Unsplash</a>)</p>
<p>People in tech think this phrase is limited to them. They haven't met a newly trained make-up artist go for his/her first gig. </p>
<p>I was one of the few people in my class (back in uni) that really enjoyed programming. I was confident I knew things but at the same time, I didn't know a lot. I remember when I started learning Android development, I quickly updated my resume and LinkedIn skillset to include it. Twice I was asked about my level of competence in that skill but I couldn't defend it.</p>
<p>In 2019/20, I challenged myself to learn and practice more. I got exposed to people in the tech space and working in teams shed more light on best practices. During my first team project, I used a <em>fake it till you make it</em> approach. I also got a mentor.</p>
<p>Imposter syndrome makes you doubt yourself but that doubt should translate into growing your skills.</p>
<p><strong>Lessons:</strong></p>
<ol>
<li>Start believing in yourself.</li>
<li>Practise makes perfect.</li>
<li>Ask questions in doubt and follow the right people.</li>
</ol>
<h2 id="too-many-technologies-to-keep-up-with">Too many technologies to keep up with</h2>
<p>Keeping up with the constant evolution in tech is not easy; it's not mandatory to pick up every new tool released but having knowledge of various tools gives you flexibility in what you can do and command.</p>
<p>In university, I explored <code>Visual Basic -&gt; C -&gt; C++ -&gt; Python -&gt; C# -&gt; HTML, CSS &amp; JS -&gt; PHP -&gt; Java</code>. I mainly used them to solve arithmetic problem but I took a deeper dive into the last 3 technologies.</p>
<p>After university, I started exploring Android, NodeJS and TypeScript. There's so much more I want to learn; learning gets exhausting. I've enrolled in many courses on Udemy, Coursera, Datacamp, Pluralsight, edX, API Academy and maybe a few more that I don't even remember. When I enrolled, I was "saving them for a rainy day" but I will never finish them.</p>
<p>The key thing is planning. I know I can't possibly learn 5 new technologies while trying to maintain a social life and working full-time in a short period. I don't want to be a mad scientist and lose my mind. I  plan my learning path so as to maximise effort and get the best out of the learning process.</p>
<p><strong>Lessons:</strong></p>
<ol>
<li>The road to your destination is never straightforward.</li>
<li>Seek help if you're stuck.</li>
<li>Working in a team is a great way to learn.</li>
<li>Plan your learning path and be realistic about the time you have.</li>
</ol>
<h2 id="job-rejections">Job rejections</h2>
<p>You don't want to know how many jobs I've applied to and got rejected from since I graduated from the university because they're many. The majority were outright rejections, "you do not qualify", no response from some, didn't pass the tests or didn't get to the final stage for others. You'd think just finishing from schools means you're still "hot and fresh" and so you'll be rushed. Sadly, this doesn't favour every graduate.</p>
<p>Looking back, I realised that I didn't have enough knowledge base (but I was a fresh graduate. Was I supposed to have 10 years of experience?). I decided to be more purposeful about what I wanted and targetted them. I started blogging as another way to show my technical competence and got involved in communities where I met people who can vouch for me.</p>
<p><strong>Lessons:</strong></p>
<ol>
<li>Build your skill and your network.</li>
<li>Be specific about where you want to be and work towards it.</li>
</ol>
<h2 id="closing-remarks">Closing remarks</h2>
<p>All the things I faced made me stronger and more confident. I wouldn't change anything because my challenges paved a way for me to see clearly what I want. If carbon has to be subjected to intense pressure, temperature and other factors to produce the beautiful diamond that you see today, humans as well have to go through a refining process to become the best versions of themselves.</p>
<h2 id="resources">Resources</h2>
<p><span>Cover Image by <a href="https://unsplash.com/@bradencollum?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Braden Collum</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Journey in Tech: How it started vs How it's going]]></title><description><![CDATA[For as long as I can remember, computers fascinated me. The idea of an object I can play with and not rip apart like I did my dolls was it for me. Somehow, I had ample time to be in the computer room in my primary school and this only increased my fa...]]></description><link>https://blog.murewaashiru.com/journey-in-tech-how-it-started-vs-how-its-going</link><guid isPermaLink="true">https://blog.murewaashiru.com/journey-in-tech-how-it-started-vs-how-its-going</guid><category><![CDATA[General Advice]]></category><category><![CDATA[WomenWhoTech]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Mon, 21 Dec 2020 09:40:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1608543340874/N64AoXlMW.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For as long as I can remember, computers fascinated me. The idea of an object I can play with and not rip apart like I did my dolls was it for me. Somehow, I had ample time to be in the computer room in my primary school and this only increased my fascination. I was either playing games, fastening up my typing speed on Microsoft word, or creating awesome PowerPoint presentations. My high school days, unfortunately, did not give room for much experimentation.</p>
<p>I decided I was going to study something computer-related at the university; at first, it was <em>computer programming</em> but that's not an actual first-degree field so I opted for Management Information System (a breed of computer science and business management).</p>
<h2 id="heading-the-actual-genesis">The actual genesis</h2>
<p>I wrote my first line of code in 2014; the typical <em>Hello world</em>, with Visual Basic. My university was very committed to growing the programming skills of its students. For the first 3 years, we did 1 or 2 programming languages per semester.</p>
<blockquote>
<p>Visual Basic -&gt; C -&gt; C++ -&gt; Python -&gt; C# -&gt; HTML, CSS &amp; JS -&gt; PHP -&gt; Java</p>
</blockquote>
<p>Seems like a lot, right? It actually was. It was a challenge but it was nice having to skim through them all to know what I would and won't like. I mainly explored Java, PHP, and HTML, CSS &amp; JS.</p>
<h2 id="heading-after-school">After school</h2>
<p>I resumed work the week following my convocation. I  hoped to get into a programming role but I wasn't ready to face C# so I chose the Business Analysis path. I had to build a simple desktop calculator with C# before my confirmation. It was pretty sleek. I would've put the source code on Github but when I wrote the code, God and I both understood it, now, only God understands it.</p>
<p>Being a business analyst means being the bridge between the developers and the customers. I was (still am) in a position of thinking business-wise and thinking programming-wise; having a programming bias made it easier to break down requirements into the most minute scenarios. It really extended my analytical capabilities. The field is actually very good as it builds dual capacity. No one ever runs a company successfully without having a good business acumen; the earlier you can pick it up, the better for you. Business analysis is also one of the <a target="_blank" href="https://business.linkedin.com/talent-solutions/blog/trends-and-research/2020/most-in-demand-hard-and-soft-skills">Top 10 Hard skills of 2020</a> by LinkedIn.</p>
<p>In 2019, I decided to rekindle my romance with programming by enrolling in the GADS and DevC (Andela + Facebook Developer Circle) programs for Android and web development respectively. I was introduced to Node.js by the latter and I am hopelessly in love with it. I also got myself a tech mentor.</p>
<p>In 2020, I participated in 3 remote internships and 1 hackathon. I integrated myself into so many tech communities and built networks, it's amazing. 
I also started blogging here on Hashnode because of <a target="_blank" href="https://hashnode.com/@didicodes">Edidiong Asikpo</a> and it's really pushed me to learn more and share. My first <a target="_blank" href="https://www.linkedin.com/feed/update/urn:li:activity:6742526938931322880/">tech talk</a> and Open Source contribution also happened this year.</p>
<p>I'd like to believe that my growth so far has been biased to business analysis, software development (backend), and technical writing, but that's not all I'm about.</p>
<h2 id="heading-going-forward">Going forward</h2>
<p>There's still so much to be done and I'm very committed to constant growth and exploits. Tech is my going concern. I would say I hope to be the next Mark Zuckerberg but I'd rather be the very best version of me.</p>
<h2 id="heading-resources">Resources</h2>
<p><a target="_blank" href="https://unsplash.com/photos/EbPso3cWlaI">Cover Image</a></p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> / <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> / <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Payment Service Integration- 200 countries covered]]></title><description><![CDATA[Hope I didn't give you a scare with 200 countries. Whoop! Don't worry, you're safe.
Handling payments for goods and services rendered back in the days was a very long and tedious process, prone to errors and time-consuming. Queuing at the bank or cha...]]></description><link>https://blog.murewaashiru.com/payment-service-integration-200-countries-covered</link><guid isPermaLink="true">https://blog.murewaashiru.com/payment-service-integration-200-countries-covered</guid><category><![CDATA[Node.js]]></category><category><![CDATA[Business and Finance ]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sat, 12 Dec 2020 16:25:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607789254354/AR86jcRVL.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hope I didn't give you a scare with <strong>200 countries</strong>. Whoop! Don't worry, you're safe.</p>
<p>Handling payments for goods and services rendered back in the days was a very long and tedious process, prone to errors and time-consuming. Queuing at the bank or chasing customers to receive money is a job for the strong-minded and 'stress-tolerant'. As technology evolved over the years, the financial sector also joined the ride. Individuals and corporates can send and receive money from the comfort of their homes thus making life easier for everyone.</p>
<p>Payment service refers to any service provided by a financial institution to allow one person or organization to pay another for a product or service. In this article, we'll be looking at 3 payment service providers who operate in about 200 countries. </p>
<p>Code snipped will be shared however the full code can be found <a target="_blank" href="https://github.com/murewaashiru/payment-service-integrations">here</a>.</p>
<h2 id="paystack">Paystack</h2>
<p><a target="_blank" href="www.paystack.com">Paystack</a> was founded in 2015 by 2 Nigerians but acquired by Stripe in October 2020. It provides online payment facilities to merchants and others by way of an API and a few lines of code. It supports the B2B and B2C business models, and thus a wide range of businesses. It currently has over 60,000 businesses using its services.</p>
<p>Paystack supports payment using debit cards, bank transfer, USSD, mobile money and visa QR. It currently operates in Nigeria, Ghana and South Africa, supporting the following currencies: NGN, USD, GH₵ and ZAR.</p>
<p><strong>Pros</strong></p>
<ol>
<li>It is easy to integrate.</li>
<li>It supports various business models.</li>
<li>It provides customer support.</li>
<li>No set-up fees.</li>
<li>You can set up recurring payments.</li>
</ol>
<p><strong>Cons</strong></p>
<ol>
<li>It does not support cross-currency transactions.</li>
<li>Transaction settlement is T+1 (the day after the transaction). Settlement only occurs during the weekdays.</li>
</ol>
<pre><code><span class="hljs-comment">// Initialise transaction</span>
app.post(<span class="hljs-string">'/transaction'</span>, <span class="hljs-keyword">async</span>(req, res)=&gt;{   
      <span class="hljs-keyword">const</span> paymentData = {
        <span class="hljs-attr">email</span>:<span class="hljs-string">'johndoe@gmail.com'</span>,
        <span class="hljs-attr">amount</span>:<span class="hljs-number">10000</span>,  <span class="hljs-comment">// In kobo</span>
        <span class="hljs-attr">reference</span>: <span class="hljs-string">`ABDC-<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>`</span>,
        <span class="hljs-attr">metadata</span>: {
            <span class="hljs-attr">custom_fields</span>: [
                {
                    <span class="hljs-attr">full_name</span>: <span class="hljs-string">'John Doe'</span>,
                }
            ]
        }
    }

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/transaction/initialize'</span>, { ...paymentData });
    <span class="hljs-keyword">const</span> result =  response.data.data

    <span class="hljs-keyword">return</span> res.json({result})
})
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607614759953/cP5o2-Rw9.png" alt="image.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607615372966/ICZ78H8Nj.png" alt="rm.png" /></p>
<h2 id="paypal">PayPal</h2>
<p><a target="_blank" href="https://www.paypal.com">Paypal</a> is an electronic commerce company that facilitates payments between parties through online transfers. Users create an account on its platform, which is connected to their credit card or checking account. Users can send or receive payments to and from other PayPal accounts online or through the company's app.</p>
<p>PayPal offers payment services and solutions for both personal consumers and businesses. The company allows personal consumers to shop, make payments, and transfer money with relative ease. Users need an email address to sign up for an account and must provide a credit card, debit card, or bank account to complete the setup.</p>
<p>PayPal verifies all information to make sure the person setting up the account is the rightful owner before the service can be used. lt is available in over 200 countries and regions.</p>
<p><strong>Pros</strong></p>
<ol>
<li>It is easy to integrate.</li>
<li>It supports various business models.</li>
<li>No set-up fees.</li>
<li>It offers its own credit card through Synchrony Bank. Approved applicants are supplied with MasterCards branded with the PayPal name.</li>
<li>Cross-currency transactions are supported.</li>
<li>You can create and send invoices right through your account.</li>
</ol>
<p><strong>Cons</strong></p>
<ol>
<li>Some transaction settlements are not real-time; differs between countries</li>
<li>PayPal can freeze accounts without warning. PayPal’s algorithm can sometimes detect suspicious behaviours in your account. And when that happens, PayPal can automatically freeze your account, along with the funds in the account.</li>
<li>There are hefty fees for chargebacks.</li>
<li>PayPal's Seller Protection policies do not cover digital goods.</li>
</ol>
<pre><code><span class="hljs-comment">// create order</span>
app.post(<span class="hljs-string">'/order'</span>, <span class="hljs-keyword">async</span>(req, res)=&gt;{
    <span class="hljs-keyword">const</span> paymentData = {
      intent: <span class="hljs-string">"CAPTURE"</span>,  <span class="hljs-comment">// CAPTURE or AUTHORIZE</span>
      purchase_units: [
        {
          amount: {
            currency_code: <span class="hljs-string">"USD"</span>,
            value: <span class="hljs-string">"100.00"</span>
          }
        }
      ]
    }

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">'/v2/checkout/orders'</span>, { ...paymentData }, {...headers});
    <span class="hljs-keyword">const</span> result = response.data
    <span class="hljs-keyword">return</span> res.json({result})
})
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607616015107/SELmHRI01.png" alt="Response.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607616177175/6zjfv09c2.png" alt="Checkout.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607616276577/8wZq9N_-Y.png" alt="Checkout2.png" /></p>
<h2 id="eway">eWay</h2>
<p><a target="_blank" href="https://www.eway.com.au/">eWay</a> was launched in 1998. It is an omnichannel payment provider. The company processes secure credit card payments for merchants and works through eCommerce.</p>
<p>eWAY processes payments for over 26,000 businesses.</p>
<p><strong>Supported platforms</strong> include
Magento, Shopify, WooCommerce, BigCommerce, WP e-commerce, etc.</p>
<p><strong>Pros</strong></p>
<ol>
<li>Built-in fraud prevention tool</li>
<li>Approved merchants don’t need a merchant account</li>
<li>No set-up fees</li>
<li>Transactions are risk-rated in real-time via the Beagle tool (a free plan)</li>
<li>APIs are secure and robust, thus eWay can be integrated with almost any website on the planet.</li>
</ol>
<p><strong>Cons</strong></p>
<ol>
<li>Their built-in fraud prevention tool has to be manually activated from your merchant account.</li>
<li>Only merchants with bank accounts based in Australia, New Zealand, Singapore, Hong Kong, Malaysia, and the UK can use eWay to receive payments.</li>
</ol>
<pre><code><span class="hljs-comment">// charge token customer</span>
app.post(<span class="hljs-string">'/transaction'</span>, <span class="hljs-keyword">async</span>(req, res)=&gt;{
    <span class="hljs-keyword">const</span> paymentData = {
      <span class="hljs-string">"Customer"</span>: {
        <span class="hljs-string">"TokenCustomerID"</span>: <span class="hljs-number">917758625852</span>
      },
      <span class="hljs-string">"Payment"</span>: {
        <span class="hljs-string">"TotalAmount"</span>: <span class="hljs-number">1000</span>
      },
      <span class="hljs-string">"TransactionType"</span>: <span class="hljs-string">"Recurring"</span>
    }

    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.createTransaction(rapid.Enum.Method.DIRECT, paymentData);
    <span class="hljs-keyword">const</span> result = response.attributes;
    <span class="hljs-keyword">return</span> res.json({result})
})
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607617268409/E4P31piCv.png" alt="Response.png" /></p>
<h2 id="contribution">Contribution</h2>
<p>If you notice a bug or would like to contribute, feel free to reach out to me or check out the <em>Contribution</em> section of the  <a target="_blank" href="https://github.com/murewaashiru/payment-service-integrations">repo</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Payment service providers have made life easier for persons to conduct local and international businesses and receive payment. Now you have no excuse for not starting your business.
Go ahead and practise what we've covered in this article, or explore from the hundreds of PSPs that exist.</p>
<p><strong>Note</strong>
All information is at the date of this publication (December 2020) as is subject to review with innovations from the various PSPs.</p>
<h2 id="resources">Resources</h2>
<ol>
<li><a target="_blank" href="https://craft.co/paystack">Paystack</a></li>
<li><a target="_blank" href="https://www.webalive.com.au/payment-gateway-australia/">Top 6 Payment Gateways for Online Businesses in Australia</a> </li>
<li><a target="_blank" href="https://www.investopedia.com/terms/p/paypal.asp">PayPal</a></li>
<li><a target="_blank" href="https://financialwellness.org/paypal-pros-cons-review/">PayPal pros and cons</a></li>
</ol>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[My Experience at the Hashnode Technical Writing Bootcamp]]></title><description><![CDATA[Being a business analyst means a lot of writing. So, I can say I've been into technical writing since 2018, but I didn't realize it until 2020. I saw it as boring. Some of my colleagues teased me, 'All you do is write documents', 'Why is your screen ...]]></description><link>https://blog.murewaashiru.com/my-experience-at-the-hashnode-technical-writing-bootcamp</link><guid isPermaLink="true">https://blog.murewaashiru.com/my-experience-at-the-hashnode-technical-writing-bootcamp</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[#⛺the-technical-writing-bootcamp]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sun, 25 Oct 2020 11:55:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1603627437762/ihmpmbBK2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Being a business analyst means a lot of writing. So, I can say I've been into technical writing since 2018, but I didn't realize it until 2020. I saw it as boring. Some of my colleagues teased me, 'All you do is write documents', 'Why is your screen always white?' I let it get to me because I thought I was the least important on the chain of importance not realizing how valuable I actually am.</p>
<p>In 2020, I signed up on Hashnode and I got the chance to attend the first Technical Writing Bootcamp. It was a great experience and I met 4 amazing writers ( <a target="_blank" href="https://hashnode.com/@Catalinpit">Catalin Pit</a>, <a target="_blank" href="https://hashnode.com/@omotola">Omotola Shogunle</a>,  <a target="_blank" href="https://hashnode.com/@atapas">Tapas Adhikary</a>  &amp;  <a target="_blank" href="https://hashnode.com/@victoria">Victoria Lo</a> ) who have helped shape &amp; streamline my thoughts &amp; expectations on technical writing.</p>
<p>Some of the points I picked up from the bootcamp include but are not limited to:</p>
<ul>
<li>Knowing your audience and writing to fit their needs.</li>
<li>Discovering your writing style.</li>
<li>Writing consistently.</li>
<li>Branding your blog.</li>
<li>Promoting your blog. There's no point in writing and not sharing your articles.</li>
<li>Writing as a way of improving as a developer.</li>
<li>Focusing on writing quality articles.</li>
</ul>
<p>Your blog is your persona, a reflection of who you are and what you know.</p>
<p>Thanks to the speakers and the entire Hashnode team for providing this opportunity. The journey has only begun.</p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Node.js and PostgreSQL without an ORM]]></title><description><![CDATA[Object-Relational Mapping (ORM)  is a technique that lets you query and manipulate data from a database using an object-oriented paradigm. 
An object-relational mapper (ORM) is a code library that automates the transfer of data stored in the database...]]></description><link>https://blog.murewaashiru.com/nodejs-and-postgresql-without-an-orm</link><guid isPermaLink="true">https://blog.murewaashiru.com/nodejs-and-postgresql-without-an-orm</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Thu, 22 Oct 2020 11:02:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1603364914733/h0KAsRvrJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p> <a target="_blank" href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">Object-Relational Mapping (ORM)</a>  is a technique that lets you query and manipulate data from a database using an object-oriented paradigm. </p>
<p>An object-relational mapper (ORM) is a code library that automates the transfer of data stored in the database into objects that are more commonly used and understandable in application code, so you don't use SQL. e.g. sequelize, typeORM, Pony, etc.</p>
<p>You have an <em>article</em> class, you want to retrieve all the articles with the title "ORM". With SQL, it would look like this:</p>
<pre><code>const query = "<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> article <span class="hljs-keyword">WHERE</span> title=<span class="hljs-string">'ORM'</span>;";
const data = await pool.query(query);
</code></pre><p>With an ORM library, it would look like this:</p>
<pre><code><span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span>= await Article.findOne({
      <span class="hljs-keyword">where</span>: { title: <span class="hljs-string">"ORM"</span> },
    });
</code></pre><p>In this article, we will be creating a simple Article CRUD app, writing raw SQL queries to manipulate data.</p>
<h2 id="pre-requisite">Pre-requisite</h2>
<p>The following should be installed on your computer:</p>
<ol>
<li>PostgreSQL</li>
<li>Node.js</li>
<li>Postman</li>
</ol>
<h2 id="database-set-up">Database Set-Up</h2>
<p>1) Launch <code>SQL shell (psql)</code></p>
<p>2) Click on <code>Enter</code> after every line. Enter your password when prompted.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603314952975/RMcGXrCUw.png" alt="image.png" /></p>
<p>3) Create a database
<code>CREATE DATABASE node_pg_test;</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603320827313/VLRSN2pb2.png" alt="image.png" />
4) Connect to the database</p>
<pre><code>\<span class="hljs-built_in">c</span> node_pg_test
</code></pre><p>5) Create article table</p>
<pre><code><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> article(
 <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>, 
title <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>, 
article <span class="hljs-built_in">TEXT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>, 
created_on <span class="hljs-built_in">TIMESTAMP</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CURRENT_TIMESTAMP</span>);
</code></pre><p>Run <code>\dt</code> to check all the tables we have.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603320914729/Ng47Ly-u7.png" alt="image.png" />
That's all for our database. Let's head over to the text editor to write our code.</p>
<h2 id="project-structure">Project Structure</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603321265992/4Sq9tX2J1.png" alt="image.png" /></p>
<p>.env =&gt; Contains all the environment variables (e.g. PORT and database URL)</p>
<p>config.js=&gt; Contains connection to the database.</p>
<p>controller.js=&gt; Contains functions to handle specific operations.</p>
<p>index.js =&gt; The starting point that connects all parts of the app together.</p>
<p>route.js =&gt; Contains the routing for the endpoints.</p>
<h2 id="set-up-your-code-and-install-the-dependencies">Set-up your code and install the dependencies</h2>
<p>1) Create a folder that you want to work in and cd into it</p>
<p>2) Run <code>npm init -y</code>. This will accept the default config.</p>
<p>3) Install all the required dependencies</p>
<pre><code><span class="hljs-built_in">npm</span> install dotenv express pg
<span class="hljs-built_in">npm</span> install -D nodemon
</code></pre><p>4) Update the start script in <code>package.json</code></p>
<pre><code><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>:<span class="hljs-string">"node index.js"</span>,
    <span class="hljs-string">"dev"</span>:<span class="hljs-string">"nodemon index.js"</span>
  },
</code></pre><p>5) Create a <code>.env</code> file </p>
<pre><code>// .env
//DATABASE_URL_FORMAT= postgresql://{<span class="hljs-keyword">user</span>}:{<span class="hljs-keyword">password</span>}@{host}:{port}/{<span class="hljs-keyword">database</span>}
DATABASE_URL = postgresql://postgres:{<span class="hljs-keyword">password</span>}@localhost:<span class="hljs-number">5432</span>/pg_node_test
</code></pre><p>6) Filling in the blanks</p>
<pre><code><span class="hljs-comment">// index.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-keyword">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> bodyParser = <span class="hljs-keyword">require</span>(<span class="hljs-string">"body-parser"</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-keyword">require</span>(<span class="hljs-string">'dotenv'</span>)
<span class="hljs-keyword">const</span> articleRouter = <span class="hljs-keyword">require</span>(<span class="hljs-string">"./route"</span>);

dotenv.config();

app.<span class="hljs-keyword">use</span>(bodyParser.json());
app.<span class="hljs-keyword">use</span>(
  bodyParser.urlencoded({
    extended: <span class="hljs-literal">true</span>
  })
);

<span class="hljs-keyword">const</span> port =  process.env.PORT || <span class="hljs-number">3000</span>

app.listen(port,() =&gt;{
    console.log(<span class="hljs-string">'Node.js listening... '</span> + port);
})
app.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/articles"</span>, articleRouter);
</code></pre><pre><code><span class="hljs-comment">//config.js</span>
<span class="hljs-keyword">const</span> Pool = <span class="hljs-built_in">require</span>(<span class="hljs-string">"pg"</span>).Pool;
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>);
dotenv.config();

<span class="hljs-keyword">const</span> pool = <span class="hljs-keyword">new</span> Pool({
  connectionString: process.env.DATABASE_URL
});

pool.on(<span class="hljs-string">"connect"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"connected to the db"</span>);
});

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  pool
};
</code></pre><pre><code><span class="hljs-comment">// controller.js</span>
<span class="hljs-keyword">const</span> { pool } = require(<span class="hljs-string">"./config"</span>);

<span class="hljs-keyword">const</span> getArticles = async (req, res, next) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span> = await pool.query(
      <span class="hljs-string">"SELECT * FROM article ORDER BY created_on DESC;"</span>
    );

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">data</span>.rowCount == <span class="hljs-number">0</span>) 
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">"No article exists"</span>);

    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
      status:<span class="hljs-number">200</span>, 
      message: <span class="hljs-string">"All articles:"</span>, 
      <span class="hljs-keyword">data</span>:<span class="hljs-keyword">data</span>.rows
    });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> next(error);
  }
};

<span class="hljs-keyword">const</span> createArticle = async (req, res, next) =&gt; {
    <span class="hljs-keyword">const</span> { title, article } = req.body;
    <span class="hljs-keyword">const</span> query =
      <span class="hljs-string">"INSERT INTO article(title, article)  VALUES($1, $2) RETURNING *;"</span>;
    <span class="hljs-keyword">const</span> values = [title, article];
    <span class="hljs-keyword">try</span>{
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span> = await pool.query(query, values);

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).json({
        status:<span class="hljs-number">201</span>, 
        message: <span class="hljs-string">"Article added successfully"</span>, 
        <span class="hljs-keyword">data</span>: <span class="hljs-keyword">data</span>.rows
      });
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">return</span> next(error);
    }
  };

<span class="hljs-keyword">const</span> getArticleById = async (req, res, next) =&gt; {
    <span class="hljs-keyword">const</span> id = parseInt(req.params.id);
    <span class="hljs-keyword">const</span> query = <span class="hljs-string">"SELECT * FROM article WHERE id=$1;"</span>;
    <span class="hljs-keyword">const</span> value = [id];

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span> = await pool.query(query, value);

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">data</span>.rowCount == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">"No article exists"</span>);

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
        status:<span class="hljs-number">200</span>, 
        message: <span class="hljs-string">"Article:"</span>, 
        <span class="hljs-keyword">data</span>: <span class="hljs-keyword">data</span>.rows
      })
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">return</span> next(error);
    }
  };

  <span class="hljs-keyword">const</span> updateArticle = async (req, res, next) =&gt; {
    <span class="hljs-keyword">const</span> id = parseInt(req.params.id);
    <span class="hljs-keyword">const</span> { title, article} = req.body;

    <span class="hljs-keyword">const</span> query =
      <span class="hljs-string">"UPDATE article SET title=$1, article=$2 WHERE id=$3 RETURNING *;"</span>;
    <span class="hljs-keyword">const</span> value = [title, article, id];

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span> = await pool.query(query, value);

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">data</span>.rowCount == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">"Article does not exist"</span>);

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
        status:<span class="hljs-number">200</span>, 
        message: <span class="hljs-string">"Article updated successfully "</span>, 
        <span class="hljs-keyword">data</span>: <span class="hljs-keyword">data</span>.rows
      })
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">return</span> next(error);
    }
  };

  <span class="hljs-keyword">const</span> deleteArticle = async (req, res, next) =&gt; {
    <span class="hljs-keyword">const</span> id = parseInt(req.params.id);
    <span class="hljs-keyword">const</span> value = [id];
    <span class="hljs-keyword">const</span> query = <span class="hljs-string">"DELETE FROM article WHERE id=$1;"</span>;

    <span class="hljs-keyword">try</span> {      
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">data</span> = await pool.query(query, value);

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">data</span>.rowCount == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">"Article does not exist"</span>);

      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
        status:<span class="hljs-number">200</span>, 
        message: <span class="hljs-string">"Article deleted successfully"</span>
      })
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">return</span> next(error);
    } 
  };

  module.exports = {
    getArticles,
    createArticle,
    getArticleById,
    updateArticle,
    deleteArticle
  };
</code></pre><pre><code><span class="hljs-comment">// route.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> router = express.Router();
<span class="hljs-keyword">const</span> {
  getArticles,
  createArticle,
  getArticleById,
  updateArticle,
  deleteArticle
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./controller"</span>);

router
    .post(<span class="hljs-string">"/"</span>, createArticle)
    .get(<span class="hljs-string">"/"</span>, getArticles);
router.get(<span class="hljs-string">"/:id"</span>, getArticleById);
router.patch(<span class="hljs-string">"/:id"</span>, updateArticle);
router.delete(<span class="hljs-string">"/:id"</span>, deleteArticle);

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = router;
</code></pre><p>Let's start the development server using <code>npm run dev</code> and test in Postman. 
The base URL is <code>http://localhost:4000/articles</code></p>
<h2 id="conclusion">Conclusion</h2>
<p>Although using ORMs makes life much easier and your code cleaner, being able to write SQL queries is a very essential skill. Writing SQL queries makes using ORMs more understandable. Simple and complex data manipulation can be done using SQL. </p>
<h2 id="resources">Resources</h2>
<p>1)  <a target="_blank" href="https://www.postgresqltutorial.com/connect-to-postgresql-database/">Connect To a PostgreSQL Database Server</a> </p>
<p>2)  <a target="_blank" href="https://www.guru99.com/postgresql-create-database.html">PostgreSQL CREATE DATABASE with Example</a></p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Exploring The Movie DB in Node.js]]></title><description><![CDATA[TMDB  is a free movie database. Although you can't actually watch movies from it, it provides a lot of data for its movies (rating, creator, actors, release date, etc). The best part is that their API is available to the public for integration.
In th...]]></description><link>https://blog.murewaashiru.com/exploring-the-movie-db-in-nodejs</link><guid isPermaLink="true">https://blog.murewaashiru.com/exploring-the-movie-db-in-nodejs</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sun, 18 Oct 2020 13:45:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1603208584437/Td5C98VRP.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p> <a target="_blank" href="https://www.themoviedb.org/.">TMDB </a> is a free movie database. Although you can't actually watch movies from it, it provides a lot of data for its movies (rating, creator, actors, release date, etc). The best part is that their API is available to the public for integration.</p>
<p>In this article, we'll be exploring TMDB in Node.js.</p>
<p>Before we being any coding, let's take a look at the  <a target="_blank" href="https://developers.themoviedb.org/3/movies/get-popular-movies">TMDB API Documentation</a>. There are dozens of categories available to us- movies, companies, TV series, reviews, etc. Is there anything they don't have? Take a moment and explore the documentation to have a good idea of what you can build with it.</p>
<h2 id="pre-requisite">Pre-requisite</h2>
<p>1) <a target="_blank" href="https://www.themoviedb.org/">TMDB</a>  account. Register for an API key as you would need it.</p>
<p>2) Postman</p>
<p>Now that that's set-up. Let's get to it.</p>
<h2 id="install-the-required-dependencies">Install the required dependencies</h2>
<p>Let's install express, dotenv, axios and nodemon</p>
<pre><code><span class="hljs-comment">//.env</span>
MOVIE_DB_API_KEY=
</code></pre><pre><code>app.js
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);
<span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);

dotenv.config();

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-keyword">const</span> server = app.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server listening on port <span class="hljs-subst">${server.address().port}</span>`</span>);
});

app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">_, res</span>)=&gt;</span>{
    res.send(<span class="hljs-string">'hi'</span>)
})
</code></pre><p>In <code>package.json</code>, update your start script, add <code>"dev": "nodemon app.js"</code>
Run <code>npm run dev</code> to start the app. </p>
<p>Head over to postman and make a request to <code>http://localhost:4000/</code>. If you get <code>Hi</code> as your response, you're good. </p>
<h2 id="exploring-popular-movieshttpsdevelopersthemoviedborg3moviesget-popular-movies">Exploring  <a target="_blank" href="https://developers.themoviedb.org/3/movies/get-popular-movies">Popular Movies</a></h2>
<p>This API is used to get a list of the current popular movies on TMDb. This list updates daily.</p>
<p>Add the below to <code>app.js</code></p>
<pre><code><span class="hljs-comment">/**
 * Fetch popular movies from TMDB
 *  <span class="hljs-doctag">@returns <span class="hljs-type">{Array}</span> <span class="hljs-variable">movies</span></span>
 */</span>
<span class="hljs-keyword">const</span> fetchMovies = <span class="hljs-keyword">async</span> (page) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">let</span> result;
      <span class="hljs-keyword">await</span> axios
        .get(
          <span class="hljs-string">`https://api.themoviedb.org/3/movie/popular?api_key=<span class="hljs-subst">${process.env.MOVIE_DB_API_KEY}</span>&amp;page=<span class="hljs-subst">${page}</span>`</span>
        )
        .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
          result = response.data.results;
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(error);
        });
      <span class="hljs-keyword">return</span> result;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
    }
  };

app.get(<span class="hljs-string">'/movies'</span>, <span class="hljs-keyword">async</span> (req, res, next)=&gt;{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> {page} = req.query;
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchMovies(page);

        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
          <span class="hljs-attr">status</span>:<span class="hljs-number">200</span>,
          <span class="hljs-attr">message</span>: <span class="hljs-string">`<span class="hljs-subst">${data.length}</span> movies found`</span>, 
          data
        })
      } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> next(err);
      }
})
</code></pre><p>We created fetchMovies(page) to interface with TMDB endpoint and get the movies. The endpoint returns a list of things, some of which we don't need, therefore, we specified only what we want to return to the user <code>result = response.data.results;</code>. Then we call the method in our <code>/movies</code> route.</p>
<p>The <em>page</em> query parameter is optional but the result will default to page 1 if removed. Each page returns 20 movies and there are 1,000 pages.</p>
<p>Let's try it in Postman.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603025693385/ogiFUKXLg.png" alt="image.png" /></p>
<h2 id="exploring-genreshttpsdevelopersthemoviedborg3moviesget-popular-movies">Exploring  <a target="_blank" href="https://developers.themoviedb.org/3/movies/get-popular-movies">Genres</a></h2>
<p>This endpoint gets the list of official genres for movies.</p>
<pre><code><span class="hljs-comment">//app.js</span>
<span class="hljs-comment">/**
 * Fetch genres from the moviedb.org
 *  <span class="hljs-doctag">@returns <span class="hljs-type">{Array}</span> </span>list of genres
 */</span>
<span class="hljs-keyword">const</span> fetchGenres = <span class="hljs-keyword">async</span> (page) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">let</span> result;
      <span class="hljs-keyword">await</span> axios
        .get(
          <span class="hljs-string">`https://api.themoviedb.org/3/genre/movie/list?api_key=<span class="hljs-subst">${process.env.MOVIE_DB_API_KEY}</span>`</span>
        )
        .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {   
          result = response.data.genres;
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(error);
        });
      <span class="hljs-keyword">return</span> result;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
    }
  };
<span class="hljs-comment">// Get Genres</span>
app.get(<span class="hljs-string">'/genres'</span>, <span class="hljs-keyword">async</span> (req, res, next)=&gt;{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchGenres();

        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
          <span class="hljs-attr">status</span>:<span class="hljs-number">200</span>,
          <span class="hljs-attr">message</span>: <span class="hljs-string">`<span class="hljs-subst">${data.length}</span> genres found`</span>, 
          data
        })
      } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> next(err);
      }
})
</code></pre><p>Let's try it in Postman.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1603028443872/RQVe6RR6R.png" alt="image.png" /></p>
<h2 id="whats-next">What's next?</h2>
<p>Not that you have an introduction to TMDB, go ahead and integrate to more endpoints, create your own application that requires TMDB.</p>
<h2 id="resources">Resources</h2>
<p> <a target="_blank" href="https://www.themoviedb.org/documentation/api">TMDB API Documentation</a> </p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Regex in short]]></title><description><![CDATA[Regex, short for regular expression, is a sequence of characters that define a pattern. It is very powerful and used in string manipulation, validation and search. By default, regex is embedded in every programming language. 
Using regex can be confu...]]></description><link>https://blog.murewaashiru.com/regex-in-short</link><guid isPermaLink="true">https://blog.murewaashiru.com/regex-in-short</guid><category><![CDATA[General Programming]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[Regex]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Fri, 16 Oct 2020 22:39:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1616421841577/9ed9VP4dG.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Regex, short for <em>regular expression</em>, is a sequence of characters that define a pattern. It is very powerful and used in string manipulation, validation and search. By default, regex is embedded in every programming language. </p>
<p>Using regex can be confusing. As such, it's important to know your expectation before attempting to implement it. <a target="_blank" href="https://regexr.com/">Regexr</a> is an online tool to evaluate regex. Open this in another tab while following through this article.</p>
<h2 id="building-blocks-of-regex">Building blocks of regex</h2>
<p><strong>A) Expression Pattern: </strong> Brackets are used to find a range of characters.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602878709131/-m6NpbYeZ.png" alt="image.png" /></p>
<p><strong>B) Metacharacter: </strong> Metacharacters are characters with a special meaning.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602879152005/anSMoK1jy.png" alt="image.png" /></p>
<p><strong>C) Quantifiers: </strong> Define quantities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602879340701/kX9dYzL4Y.png" alt="image.png" /></p>
<h2 id="some-examples">Some examples</h2>
<pre><code>"123".search(/^[a-zA-Z]+$/) // false=&gt; Capital and small letters required
"AaBbCc".search(/^[a-zA-Z]+$/) // true 

"123".search(/./) // true =&gt; Any character
"123".search(/^[0-9]{10}/) // false=&gt; Numbers with a count of 3`

"1234567890".search(/^[0-9]{10}/) // true =&gt; Numbers with a count of 10

"01-01-2020".search(/^(0?[<span class="hljs-string">1-9</span>]|[<span class="hljs-string">12</span>][<span class="hljs-symbol">0-9</span>]|3[<span class="hljs-string">01</span>])[<span class="hljs-string">\/\-</span>](<span class="hljs-link">0?[1-9]|1[012]</span>)[<span class="hljs-string">\/\-</span>]\d{4}$/) // true =&gt; Date format: dd-mm-yyyy or dd/mm/yyyy

"Password1!".search(/^(?=.<span class="hljs-emphasis">*[a-z])(?=.*</span>[A-Z])(?=.<span class="hljs-emphasis">*[0-9])(?=.*</span>[!<span class="hljs-emphasis">_`,/@#\-"=:;~<span class="xml"><span class="hljs-tag">&lt;&gt;</span></span>'\$%\^&amp;\*\?\|\+\(\)\[\]\{}\.])(?=.{8,})/) //true =&gt; Password of 8 characters including numbers, letters and symbols</span>
</code></pre><p>Note: Using <code>.search()</code> produces a 0 or -1 result. <strong>0</strong> represents <strong>true</strong> while <strong>-1</strong> represents <strong>false</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602874264061/Xc5lAT3C6.jpeg" alt="20201009_130511.jpg" /></p>
<h2 id="whats-next">What’s Next</h2>
<p>Now that you've gotten a taste of regular expressions, you can try them on your own, delving into more complicated patterns.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://www.w3schools.com/java/java_regex.asp">Java Regular Expression</a> </li>
<li><a target="_blank" href="https://dev.to/lukegarrigan/regex-from-beginner-to-best-on-your-team-in-one-blog-23a1">Regex: From beginner to BEST on your team in one blog 👑</a></li>
</ul>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Uploading images in your Node.js app using Express and Cloudinary]]></title><description><![CDATA[Storing media directly in your database can be considered poor practise as it leads to the poor performance of a system, amongst other issues. To substitute for this, Cloudinary was developed.

Cloudinary is an end-to-end image- and video management ...]]></description><link>https://blog.murewaashiru.com/uploading-images-in-your-nodejs-app-using-express-and-cloudinary</link><guid isPermaLink="true">https://blog.murewaashiru.com/uploading-images-in-your-nodejs-app-using-express-and-cloudinary</guid><category><![CDATA[Node.js]]></category><category><![CDATA[2Articles1Week]]></category><category><![CDATA[cloudinary]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sat, 10 Oct 2020 12:17:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1602332312212/3FUeEx4Qy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Storing media directly in your database can be considered poor practise as it leads to the poor performance of a system, amongst other issues. To substitute for this, Cloudinary was developed.</p>
<blockquote>
<p>Cloudinary is an end-to-end image- and video management solution for websites and mobile apps, covering everything from image and video uploads, storage, manipulations, optimizations to delivery.</p>
</blockquote>
<p>In this article, we'll be uploading images to Cloudinary in a node.js/express.js application.</p>
<h2 id="pre-requisite">Pre-requisite</h2>
<ol>
<li><a target="_blank" href="https://cloudinary.com/">Cloudinary</a> account</li>
<li>Node.js installed on your computer</li>
<li>Postman installed on your computer</li>
</ol>
<h2 id="cloudinary-configuration">Cloudinary configuration</h2>
<p>Login to your Cloudinary account. On your dashboard are 3 configurations- Cloud name, Api key and Api Secret. Copy these (into a .txt file or sticky notes) as you will need them shortly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602318805486/alO33m5if.png" alt="image.png" /></p>
<h2 id="install-the-dependencies-and-start-coding">Install the dependencies  and start coding</h2>
<p>1) Create a folder to work with. Run <code>npm init -y</code>. This will accept the default config.</p>
<p>2) Install the following dependencies- cloudinary, express, dotenv and express-fileupload</p>
<p><code>npm install cloudinary express dotenv express-fileupload</code></p>
<p>3) Create an <code>index.js</code> file which is our starting point, <code>cloudinary.js</code> file to contain the Cloudinary config and upload function, and <code>.env</code> file to contain the environment configs.</p>
<p>4) Copy the Cloudinary configs from your .txt file or sticky note and insert them in the <code>.env</code> file as seen below.</p>
<pre><code><span class="hljs-attr">CLOUDINARY_NAME</span>= insert_your_name
<span class="hljs-attr">CLOUDINARY_API_KEY</span> = insert_your_api_key
<span class="hljs-attr">CLOUDINARY_API_SECRET</span> = insert_your_api_secret
</code></pre><p>5) Connect your app to Cloudinary.</p>
<pre><code><span class="hljs-comment">// cloudinary.js</span>
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>);
<span class="hljs-keyword">const</span> cloudinary = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cloudinary'</span>).v2;

dotenv.config();

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET
});

<span class="hljs-keyword">const</span> upload = <span class="hljs-keyword">async</span> (file) =&gt; {
  <span class="hljs-keyword">const</span> image = <span class="hljs-keyword">await</span> cloudinary.uploader.upload(
    file,
    <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> result
  );
  <span class="hljs-keyword">return</span> image;
};

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = { upload };
</code></pre><p>In lines 6-8, we connected our app to cloudinary.</p>
<p>The <em>upload</em> function that handles uploading the images to cloudinary. It's good practice to have a single function that you can reuse.</p>
<p>You can also upload the images into a specific folder;</p>
<pre><code>const image = <span class="hljs-keyword">await</span> cloudinary.uploader.upload(
    file,
    { folder: <span class="hljs-string">'Test'</span> },
    <span class="hljs-function"><span class="hljs-params">(result)</span> =&gt;</span> result
  );
</code></pre><p>6) Let's make use of our upload function</p>
<pre><code><span class="hljs-comment">// app.js</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-keyword">const</span> fileUpload = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express-fileupload"</span>);
<span class="hljs-keyword">const</span> { upload } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./cloudinary'</span>)

<span class="hljs-keyword">const</span> app = express();
app.use(
    fileUpload({
      <span class="hljs-attr">useTempFiles</span>: <span class="hljs-literal">true</span>
    })
);

app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server listening on port 3000'</span>)
})

app.post(<span class="hljs-string">'/upload'</span>, <span class="hljs-keyword">async</span> (req, res)=&gt;{
    <span class="hljs-keyword">if</span> (!req.files) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">'Please upload an image'</span>);

    <span class="hljs-keyword">const</span> {image} = req.files;
    <span class="hljs-keyword">const</span> cloudFile = <span class="hljs-keyword">await</span> upload(image.tempFilePath);
    <span class="hljs-built_in">console</span>.log(cloudFile)

    res.status(<span class="hljs-number">201</span>).json({
        <span class="hljs-attr">message</span>:<span class="hljs-string">'Image uploaded successfully'</span>,
        <span class="hljs-attr">imageUrl</span>:cloudFile.url
    })
})
</code></pre><p>You can specify the file type that you want to support.</p>
<pre><code><span class="hljs-keyword">const</span> fileTypes = [<span class="hljs-string">'image/jpeg'</span>, <span class="hljs-string">'image/png'</span>, <span class="hljs-string">'image/jpg'</span>];
<span class="hljs-keyword">if</span> (!fileTypes.includes(image.mimetype)) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">'Image formats supported: JPG, PNG, JPEG'</span>);
</code></pre><p>You can also limit the size of the image to be uploaded.</p>
<pre><code><span class="hljs-keyword">const</span> imageSize = <span class="hljs-number">1024</span>;
<span class="hljs-keyword">if</span> (image.size / <span class="hljs-number">1024</span> &gt; imageSize) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">`Image size should be less than <span class="hljs-subst">${imageSize}</span>kb`</span>);
</code></pre><p>By default, the image size is in bytes. To convert to kb, divide the image by 1024.</p>
<p>Let's add the 2 options above into our route</p>
<pre><code>app.post(<span class="hljs-string">'/upload'</span>, <span class="hljs-keyword">async</span> (req, res)=&gt;{
<span class="hljs-keyword">if</span> (!req.files) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">'Please upload an image'</span>)

    <span class="hljs-keyword">const</span> {image} = req.files;
    <span class="hljs-keyword">const</span> fileTypes = [<span class="hljs-string">'image/jpeg'</span>, <span class="hljs-string">'image/png'</span>, <span class="hljs-string">'image/jpg'</span>];
    <span class="hljs-keyword">const</span> imageSize = <span class="hljs-number">1024</span>;    

    <span class="hljs-keyword">if</span> (!fileTypes.includes(image.mimetype)) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">'Image formats supported: JPG, PNG, JPEG'</span>);  

    <span class="hljs-keyword">if</span> (image.size / <span class="hljs-number">1024</span> &gt; imageSize) <span class="hljs-keyword">return</span> res.send(<span class="hljs-string">`Image size should be less than <span class="hljs-subst">${imageSize}</span>kb`</span>);

    <span class="hljs-keyword">const</span> cloudFile = <span class="hljs-keyword">await</span> upload(image.tempFilePath);
    <span class="hljs-built_in">console</span>.log(cloudFile)

    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).json({
        <span class="hljs-attr">message</span>:<span class="hljs-string">'Image uploaded successfully'</span>,
        <span class="hljs-attr">imageUrl</span>:cloudFile.url
    })
})
</code></pre><h2 id="lets-test">Let's test</h2>
<p>Run your app, typing <code>node index.js</code> in the terminal.</p>
<p>Launch Postman and make a POST request with the url- <code>http://127.0.0.1:3000/upload</code>.</p>
<p>We will test with 4 scenarios, trying to upload</p>
<p>1) Without an image
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602328563478/Getcb3PRv.png" alt="image.png" /></p>
<p>2) A file larger than 1024kb (1MB)
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602328622368/19L5vMShN.png" alt="image.png" /></p>
<p>3) A file not of type png, jpg nor jpeg
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602328795429/ulPJ2H3l2.png" alt="image.png" /></p>
<p>4) An image less than or equal to 1024kb 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602329144896/ccPdtCoDc.png" alt="image.png" /></p>
<p>If you notice, a new folder called <em>tmp</em> has been created in the root directory. This folder temporarily stores files uploaded. Cloudinary picks up the image via its file path before hosting on its server.</p>
<p>Now, let's head over to Cloudinary and see our image.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602329986064/IC67helOs.png" alt="image.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Cloudinary is a powerful tool that does much more than what we have covered in this article. I challenge you to go further and explore what more the tool has to offer.</p>
<h2 id="resources">Resources</h2>
<ol>
<li><a target="_blank" href="https://cloudinary.com/documentation/node_integration">Node.js SDK</a> </li>
</ol>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[5 Factors to consider before building a new application]]></title><description><![CDATA[You probably have a few unfinished projects sitting somewhere on your computer. Why's that? I'll give you a moment to think about it.
The mind of a developer travels far and wide, endless ideas that flow like a waterfall. Having a vivid imagination i...]]></description><link>https://blog.murewaashiru.com/5-factors-to-consider-before-building-a-new-application</link><guid isPermaLink="true">https://blog.murewaashiru.com/5-factors-to-consider-before-building-a-new-application</guid><category><![CDATA[2Articles1Week]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[General Advice]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Mon, 05 Oct 2020 20:17:38 GMT</pubDate><content:encoded><![CDATA[<p>You probably have a few unfinished projects sitting somewhere on your computer. Why's that? I'll give you a moment to think about it.</p>
<p>The mind of a developer travels far and wide, endless ideas that flow like a waterfall. Having a vivid imagination is great, but it often leads to lack of focus and abandonment of projects, as you want to do everything you think of. It's therefore very important for every developer to consider certain factors before starting a project.</p>
<p>P.S I'll be using <em>project </em>and <em>application </em>interchangeably.</p>
<h2 id="factors-to-consider">Factors to Consider</h2>
<p>These may include;</p>
<p>1) <strong>What (and why) to build?</strong>
This is the first step in accomplishing anything. What do you want to build and why?</p>
<p>Some <em>why </em>answers:</p>
<p>a. To build on existing skills </p>
<p>b. To learn a new language</p>
<p>c. To build or add to a portfolio</p>
<p>d. To create new technology and solve a problem</p>
<p>e. To contribute to open source</p>
<p>f. To make some extra cash</p>
<p>g. A school requirement</p>
<p>2) <strong>Complexity of the project:</strong> Is it simple or complex? Do you already have the requirements or research needs to be done? Can you can handle by yourself or you need a team to assist? Will there be integration to 3rd party systems? What's the best way to represent the project?</p>
<p>3) <strong>Familiarity with tools &amp; languages, and availability of reference material: </strong>  Having knowledge &amp; experience of the tools you need to build a project means less time and energy to commit. In the same light, relatively new technologies don't have as much reference materials compared to older technologies. I bet you'd find thousands of articles on <em>Python</em> that you would on <em>Deno</em>.</p>
<p>4) <strong>Time available to commit: </strong> An extremely busy person might not finish that side project he/she has started, depending on all other factors listed above. Plan your time well. Be true to yourself and the capacity to deliver within the milestones set for your project.</p>
<p>5) <strong>Cost implication:</strong> You can develop applications without spending a dime but that's limited. Integrations to certain systems have cost implications. Can you bear those costs? Are there cheaper alternatives to the systems you choose? Will your project generate enough revenue to cover the costs? Will you be able to sustain the costs in the long-term?</p>
<h2 id="conclusion">Conclusion</h2>
<p>Having said all these, don't cage your mind, don't sleep on those ideas. Write them down so you can remember them. Just maybe you'll implement one of them and be the next tech billionaire.</p>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Recursion: A Programming Concept]]></title><description><![CDATA[If you studied computer science or you're into programming, you most likely have come across the term Recursion. Quite a number of developer don't really use recursion, or perhaps it's the ones I know that don't use it. 🤔🤔
So, what is recursion?
Re...]]></description><link>https://blog.murewaashiru.com/recursion-a-programming-concept</link><guid isPermaLink="true">https://blog.murewaashiru.com/recursion-a-programming-concept</guid><category><![CDATA[#⛺the-technical-writing-bootcamp]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Murewa Ashiru]]></dc:creator><pubDate>Sat, 03 Oct 2020 20:23:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1601652298636/r_use-e6T.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you studied computer science or you're into programming, you most likely have come across the term <em>Recursion</em>. Quite a number of developer don't really use recursion, or perhaps it's the ones I know that don't use it. 🤔🤔</p>
<p>So, what is recursion?</p>
<p>Recursion is an iteration technique where a function calls itself. It's applicable when you need to call the same function repeatedly with different parameters from within a loop. </p>
<p>Search for <em>Recursion</em> on google and you get this.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601636931241/c-Q5vsvpu.png" alt="image.png" />
Now, click against the suggested <em>recursion</em>. </p>
<p>What happens? You're redirected to the same page. That's recursion with a sense of humour.</p>
<h2 id="recursion-vs-loop">Recursion vs Loop</h2>
<p>Let's take a look at 2 scenarios</p>
<p>Scenario A- Loop</p>
<pre><code><span class="hljs-keyword">const</span> pow = <span class="hljs-function">(<span class="hljs-params">x,n</span>)=&gt;</span>{
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">1</span>;

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; n; i++) {
    result *= x;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-built_in">console</span>.log( pow(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>) ); <span class="hljs-comment">// 8</span>
</code></pre><p>Scenario B- Recursion</p>
<pre><code><span class="hljs-keyword">const</span> <span class="hljs-built_in">pow</span> = (x,n)=&gt;{
  <span class="hljs-keyword">if</span> (n == <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> x;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> x * <span class="hljs-built_in">pow</span>(x, n - <span class="hljs-number">1</span>);
  }
}
console.<span class="hljs-built_in">log</span>( <span class="hljs-built_in">pow</span>(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>) ); <span class="hljs-comment">// 8</span>
</code></pre><p>What do you note between these 2 scenarios? 
In scenario A, we <em>loop</em> over the variables i.e instructions are repeatedly executed while in scenario B, the function calls itself.</p>
<p>To calculate pow(2, 3) the recursive steps are as below:</p>
<p>pow(2, 3) = 2 <em> pow(2, 2)  =&gt; 2 </em> 4 = 8</p>
<p>pow(2, 2) = 2 <em> pow(2, 1)   =&gt; 2 </em> 2 = 4</p>
<p>pow(2, 1) = 2</p>
<p>Recursion reduces a function call to a simpler one until the result is gotten.</p>
<p>It's essential to define a breakpoint (<code>n==1</code> as in the example above) else your function will run indefinitely.</p>
<h2 id="differences-between-recursion-and-loops">Differences between Recursion and Loops</h2>
<ol>
<li><strong>Time:</strong> Recursion is more time consuming than loops.</li>
<li><strong>Usage:</strong> Recursion is used when code size needs to be small, and time complexity is not an issue. A loop is used when time complexity needs to be measured against the code size.</li>
<li><strong>Termination:</strong> Recursive function is terminated when there is no function call.    A loop is terminated when the condition for the iterator ceases to be satisfied.</li>
</ol>
<h2 id="application-of-recursion">Application of Recursion</h2>
<ol>
<li>Fractal maths</li>
<li>Sorting</li>
<li>Traversing the nodes of complex or non-linear data structure</li>
<li>File trees</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>Recursion is a powerful technique and is the most direct way to solve a complex problem. However, due to its shortcomings, we will need to be very careful about how and where we apply recursion.</p>
<h2 id="references">References</h2>
<ol>
<li><a target="_blank" href="https://www.sitepoint.com/recursion-functional-javascript/#:~:text=Recursion%20is%20a%20technique%20for,to%20looping%20is%20the%20default.">Recursion in Functional JavaScript</a></li>
<li><a target="_blank" href="https://www.byte-by-byte.com/understanding-recursion/">Understanding Recursion Using Real-World Examples</a> </li>
<li><a target="_blank" href="https://www.geeksforgeeks.org/difference-between-recursion-and-iteration/">Difference between Recursion and Iteration</a> </li>
<li><a target="_blank" href="https://javascript.info/recursion">Recursion and stack</a> </li>
</ol>
<blockquote>
<p>If you like this article, feel free to comment and share. You can also reach out to me on <a target="_blank" href="https://twitter.com/rachael_xx">Twitter</a> | <a target="_blank" href="https://www.linkedin.com/in/murewageorge-ashiru/">LinkedIn</a> | <a target="_blank" href="https://github.com/murewaashiru">Github</a></p>
<p>Ciao👋🏼</p>
</blockquote>
]]></content:encoded></item></channel></rss>