<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bertrand Masabo</title>
    <description>The latest articles on DEV Community by Bertrand Masabo (@the22mastermind).</description>
    <link>https://dev.to/the22mastermind</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F374026%2F8bc3ff50-7ca1-4567-803e-2631e32111e0.png</url>
      <title>DEV Community: Bertrand Masabo</title>
      <link>https://dev.to/the22mastermind</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/the22mastermind"/>
    <language>en</language>
    <item>
      <title>Online Food Ordering App (8)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Mon, 12 Apr 2021 20:41:43 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-8-3291</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-8-3291</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Hi, welcome to the last post of Online Food Ordering App series.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In the previous posts we built API endpoints for authentication and managing orders. We've also built our frontend react and react-native apps and connected them to the API endpoints.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In this post, we are going to implement the view orders list, view single order, update order status, view menu, and place order features on our front-end apps.&lt;br&gt;&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project Steps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;1. Backend - Project Setup&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;2. Backend - Authentication - Sign Up&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;3. Backend - Authentication - Login &amp;amp; Logout&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5"&gt;4. Backend - Place Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-5-24gg"&gt;5. Backend - View Orders List &amp;amp; View a Specific Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;6. Backend - Update Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;7. Front-end - Authentication&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;8. Front-end - Place Order, View Orders List, and View Order Details&lt;/a&gt; 📌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Before we start, take a look at &lt;a href="https://github.com/the22mastermind/gourmet-api/pull/12" rel="noopener noreferrer"&gt;this PR&lt;/a&gt; and update the &lt;a href="https://github.com/the22mastermind/gourmet-api" rel="noopener noreferrer"&gt;backend code&lt;/a&gt;. We added the payments endpoint, a script to create the menu and we updated the fetch orders list to accommodate both the admin and the customer.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we begin our implementation, let's think for a minute about the user flow we want for our customer.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A logged-in customer launches the app and they immediately see a list of menu items divided into 3 tabs (Breakfast, Lunch/Dinner, and Drinks). Each item has an image, a name, a short description, a cost/price, and size. To switch to a different tab, a user swipes the screen left or right, or they tap on the tab name. To add an item to the cart, a user simply taps on the item. Tapping on the item already in the cart increases its quantity by 1. To remove an item from the cart a user simply taps on the item from the cart screen. From the cart screen, a user can navigate to the payment screen where they will be able to confirm their order by making payment by card.&lt;/em&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;A user can also see the list of orders he/she has placed and their details by tapping on the basket icon in the bottom navigator. Finally, a user will be able to see his/her account information by tapping on the account icon in the bottom navigator.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The screens of our app will be divided into 2 main parts (&lt;code&gt;AuthStack&lt;/code&gt; and &lt;code&gt;HomeStack&lt;/code&gt;) whereby &lt;code&gt;AuthStack&lt;/code&gt; will contain all the screens related to authentication (&lt;code&gt;LoginScreen&lt;/code&gt;, &lt;code&gt;SignupScreen&lt;/code&gt;, and &lt;code&gt;VerifyScreen&lt;/code&gt;) and &lt;code&gt;HomeStack&lt;/code&gt; will contain nested stacks (&lt;code&gt;MainStack&lt;/code&gt;, &lt;code&gt;OrdersStack&lt;/code&gt;, and &lt;code&gt;AccountStack&lt;/code&gt;).&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MainStack&lt;/code&gt; will contain screens allowing the user to view the menu, interact with the cart, and make a payment.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OrdersStack&lt;/code&gt; as the name suggest will contain screens for viewing the list of orders a user has placed and each order details.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AccountStack&lt;/code&gt; will contain just one screen to display the user's account information and a logout button.&lt;br&gt;&lt;/p&gt;



&lt;p&gt;Great! Let's get started.&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the dependencies we are going to need:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-native-dotenv react-native-credit-card-input react-native-paper-tabs react-native-pager-view @react-navigation/material-bottom-tabs react-native-stripe-payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the context directory, create a &lt;code&gt;dataReducer.js&lt;/code&gt; file and paste the following code inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;em&gt;&lt;code&gt;ADD_MENU&lt;/code&gt;&lt;/em&gt;: will receive an array of menu categories and their items and will save it in our state in a variable called menu.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;GET_MENU&lt;/code&gt;&lt;/em&gt;: will receive a category name then loops through the menu categories to find if that category exists then will save it's items in a variable called menuItems.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;ADD_TO_CART&lt;/code&gt;&lt;/em&gt;: will receive a menu item and append it to a variable called cart.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;UPDATE_CART&lt;/code&gt;&lt;/em&gt;: will receive an item then checks if that item is in the cart before replacing it with the new item.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;REMOVE_FROM_CART&lt;/code&gt;&lt;/em&gt;: will receive an item id then loops through the cart array to find an item with that id and delete it.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;CLEAR_CART&lt;/code&gt;&lt;/em&gt;: will remove all items in the cart array.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;ADD_ORDERS&lt;/code&gt;&lt;/em&gt;: will receive an array of orders list the save it in the state in a variable called ordersList.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;DataProvider.js&lt;/code&gt; file and paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lp5qk1qbn7nffbp5vls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lp5qk1qbn7nffbp5vls.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/navigation/menuTabs.js&lt;/code&gt; file like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7mwx0nj5uy1uakjzktw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7mwx0nj5uy1uakjzktw.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this file we create a &lt;code&gt;MenuTabs&lt;/code&gt; component that receive 2 props: &lt;code&gt;menuItems&lt;/code&gt; (an array of menu items for the selected category) and &lt;code&gt;handleChangeIndex&lt;/code&gt; (a function to switch tabs). We created a &lt;code&gt;handleAddTocart&lt;/code&gt; function which will help us to modify an item before adding it to the cart and to dispatch messages after the item is added to the cart.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The component returns 3 tab screens where each tab screen will use the &lt;a href="https://github.com/the22mastermind/gourmet/blob/main/src/components/ListItems/ListItems.js" rel="noopener noreferrer"&gt;ListItems&lt;/a&gt; component to display the data or the &lt;a href="https://github.com/the22mastermind/gourmet/blob/main/src/components/CustomCaption/CustomCaption.js" rel="noopener noreferrer"&gt;&lt;code&gt;CustomCaption&lt;/code&gt;&lt;/a&gt; component to display that items were not found. Also, each tab screen is associated with an index number starting from 0. We'll see how this index number will be useful in a minute.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let us now create the main screen and use the menu tabs we just created above.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/screens/MainScreen/MainScreen.js&lt;/code&gt; file like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F159adosptqjq0rqlhyt1.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this file we created a &lt;code&gt;MainScreen&lt;/code&gt; component that fetches user data, cart and menu items from our global state. We created a &lt;code&gt;handleChangeIndex&lt;/code&gt; function that receives an index number (tab screen index) and dispatches a function that will trigger the &lt;code&gt;GET_MENU&lt;/code&gt; action. We used the useEffect hook to trigger the handleChangeIndex function when this component mounts to get data for the first tab screen.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;This component will render a welcome message, the user's address, the menuTabs component and the &lt;a href="https://github.com/the22mastermind/gourmet/blob/main/src/components/CartButton/CartButton.js" rel="noopener noreferrer"&gt;&lt;code&gt;CartButton&lt;/code&gt;&lt;/a&gt; component to view the cart contents if the cart is not empty.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let us now create the last screen for &lt;code&gt;MainStack&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/screens/PaymentScreen/PaymentScreen.js&lt;/code&gt; file like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyuy8qbkl8nqhsl6oteu.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this file we created a &lt;code&gt;PaymentScreen&lt;/code&gt; component that has 2 functions: &lt;code&gt;handlePaymentInit&lt;/code&gt; and &lt;code&gt;handleCreditCardForm&lt;/code&gt;. When this component mounts, it displays a title, an image of credit/debit cards accepted, and a button to make payment. When the button is clicked, it triggers the &lt;code&gt;handlePaymentInit&lt;/code&gt; function which triggers an internal state update of &lt;code&gt;showCardForm&lt;/code&gt; to display the &lt;a href="https://github.com/the22mastermind/gourmet/blob/main/src/components/CreditCardForm/CreditCardForm.js" rel="noopener noreferrer"&gt;&lt;code&gt;CreditCardForm&lt;/code&gt;&lt;/a&gt; component.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CreditCardForm&lt;/code&gt; component receives an &lt;code&gt;onChange&lt;/code&gt; props which is a function that gets executed as we fill the form and returns a &lt;code&gt;formData&lt;/code&gt; object composed of 3 properties: &lt;code&gt;valid&lt;/code&gt;, &lt;code&gt;values&lt;/code&gt;, and &lt;code&gt;status&lt;/code&gt;. We are interested in &lt;code&gt;valid&lt;/code&gt; and &lt;code&gt;values&lt;/code&gt; properties.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;valid&lt;/code&gt; is a boolean which will be true once all the fields of the form are filled correctly.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;values&lt;/code&gt; is an object of the form field values. It has the following properties: &lt;code&gt;number&lt;/code&gt; (card number), &lt;code&gt;expiry&lt;/code&gt; (MM/YY), and &lt;code&gt;cvc&lt;/code&gt; (3-digit cvc/ccv). Learn more &lt;a href="https://github.com/sbycrosz/react-native-credit-card-input" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;So, in the &lt;code&gt;handleCreditCardForm&lt;/code&gt; function we check if the user has filled the form correctly, then we extract the form values and build a &lt;code&gt;cardDetails&lt;/code&gt; object. We then proceed to validate the cardDetails object by using the &lt;code&gt;isCardValid&lt;/code&gt; method from &lt;a href="https://github.com/Fitpassu/react-native-stripe-payments" rel="noopener noreferrer"&gt;react-native-stripe-payments&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If the cardDetails are valid, we hit our API endpoint for payments to create a &lt;code&gt;paymentIntent&lt;/code&gt;. The payment intent returned from calling our API contains a &lt;code&gt;clientSecret&lt;/code&gt; string that we use along with the cardDetails object to confirm the payment with stripe.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If the response returned from confirming the payment contains an id, that means the payment is successful then we proceed to prepare the payload for the order and hit our backend endpoint to place an order. If the order is placed successfully, we reset our stack navigation then navigate to ordersListScreen.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;em&gt;this implementation is a bit naive because there are some edge cases we did not account for, for example, what if the payment is successful but the order cannot be placed? What happens then?&lt;/em&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;One solution would be to extend our order statuses and allow a user to place an order before making the payment then once the payment is confirmed we approve the order.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Cool!&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we wrapped everything in a try and catch so if anything goes wrong the user will be notified via the &lt;code&gt;Alert&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; our services in &lt;code&gt;src/utils/api.js&lt;/code&gt; were starting to become messy, so we refactored the code to look like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5qiwf7nyt1vn1vy6bsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5qiwf7nyt1vn1vy6bsc.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make sure you update the authentication feature to use the updated services as well.&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The screens for our MainStack are now done. Let us implement &lt;code&gt;OrdersListScreen&lt;/code&gt; and &lt;code&gt;OrderDetailsScreen&lt;/code&gt; for &lt;code&gt;OrdersStack&lt;/code&gt; next.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/screens/OrdersListScreen/OrdersListScreen.js&lt;/code&gt; file like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7botjynvjonpd0ymp0vs.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;OrdersListScreen&lt;/code&gt; component we used the useEffect hook to add a &lt;code&gt;focus&lt;/code&gt; event listener which will be triggered every time this screen is focused. In the event listener we fetch the list of orders and dispatch an action to save the data in &lt;code&gt;ordersList&lt;/code&gt; global state variable. The component will display the list of orders if found or a no orders found text. We have also implemented a &lt;code&gt;handleOrder&lt;/code&gt; function which will receive an id then navigates to &lt;code&gt;OrderDetailsScreen&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/screens/OrderDetailsScreen/OrderDetailsScreen.js&lt;/code&gt; file like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9g60jl9w9xvwyt0c587u.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this component we fetch an order's details by using the orderId parameter from props, save the data in internal state variable orderDetails then we render the information.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The screens for &lt;code&gt;OrdersStack&lt;/code&gt; are now done. Let us create the one screen for &lt;code&gt;AccountStack&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/AccountScreen/AccountScreen.js&lt;/code&gt; file like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i01etpzg0pe2vsbmf9t.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this component we are just displaying the user information from the global state variable &lt;code&gt;auth&lt;/code&gt;. We have also moved our logout implementation in this component.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Now that our screens are done, let us create the stacks mentioned above.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/navigation&lt;/code&gt; create a new directory called &lt;code&gt;stacks&lt;/code&gt; and inside stacks create the following files: &lt;code&gt;MainStack.js&lt;/code&gt;, &lt;code&gt;OrdersStack.js&lt;/code&gt;, and &lt;code&gt;AccountStack.js&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;AccountStack.js&lt;/code&gt; paste the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmb9tefwhdk94wo1e27hn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmb9tefwhdk94wo1e27hn.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;OrdersStack.js&lt;/code&gt; paste the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpacpspiy6wa6avson7m2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpacpspiy6wa6avson7m2.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;MainStack.js&lt;/code&gt; paste the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyprchwl4held8uf1one.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyprchwl4held8uf1one.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last piece of the puzzle is to put together the stacks we created above and add the data context provider in &lt;code&gt;App.js&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's do it.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move &lt;code&gt;HomeStack.js&lt;/code&gt; in &lt;code&gt;src/navigation/stacks/&lt;/code&gt; and update it to look like this:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fciplm7izg34kl58c432e.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go over what we did in this file.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HomeStack&lt;/code&gt; is the component that will be mounted as soon as a user logs in or when a logged-in user launches the app and he/she is authenticated. There are a couple of things we want to do before this component renders:&lt;br&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need to fetch the menu and save it in our global state.&lt;/li&gt;
&lt;li&gt;While fetching the menu, if the user's token happens to be expired (from the backend) we automatically log out the user (on the frontend).&lt;/li&gt;
&lt;li&gt;If the user's token is valid and the menu data is found or not, we proceed to render the tab navigator.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, update &lt;code&gt;src/App.js&lt;/code&gt; to look like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxegw2hk9i3xs02zuj43b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxegw2hk9i3xs02zuj43b.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the app on an emulator or a physical device and you should see the screens below:&lt;/li&gt;
&lt;/ul&gt;

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

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

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

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



&lt;p&gt;&lt;em&gt;To create a splash/launch screen, check out &lt;a href="https://blog.logrocket.com/building-a-splash-screen-in-react-native/" rel="noopener noreferrer"&gt;this article&lt;/a&gt;&lt;/em&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For reference, here's &lt;a href="https://github.com/the22mastermind/gourmet" rel="noopener noreferrer"&gt;the repo&lt;/a&gt; for the project.&lt;br&gt;&lt;/p&gt;






&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Admin view orders list, view single order and update order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
For the admin app we are going to use &lt;a href="https://material-ui.com/components/tables/#collapsible-table" rel="noopener noreferrer"&gt;Material UI's Collapsible Table&lt;/a&gt; component to display the orders. Each row in the table will have a button to reveal the details where the admin will be able to see the contents of an order along with a &lt;code&gt;Update status&lt;/code&gt; and &lt;code&gt;user info&lt;/code&gt; buttons to update the status of the order and view the details of the user respectively.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;We have also implemented pagination to 5 rows per page but you can change this value according to your needs.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Great. Let's start by installing React Spring to add small animations to our app.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install React Spring:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add react-spring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;src/utils/api.js&lt;/code&gt; to look like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbslybytn5iagu2j9lpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbslybytn5iagu2j9lpx.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/pages/OrdersListPage/OrdersListPage.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ryitf5rt2z6kr6d74b0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ryitf5rt2z6kr6d74b0.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this component we fetch the list of orders from the backend then use the &lt;a href="https://github.com/the22mastermind/gourmet-admin/blob/main/src/components/CustomTable/CustomTable.js" rel="noopener noreferrer"&gt;CustomTable&lt;/a&gt; component to display the data.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;we have also used the &lt;code&gt;useSpring&lt;/code&gt; hook from &lt;a href="https://www.react-spring.io/docs/hooks/use-spring" rel="noopener noreferrer"&gt;React Spring&lt;/a&gt; to add a fade animation to our component.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Among the new &lt;a href="https://github.com/the22mastermind/gourmet-admin/tree/main/src/components" rel="noopener noreferrer"&gt;components&lt;/a&gt; we created include &lt;a href="https://github.com/the22mastermind/gourmet-admin/blob/main/src/components/CustomTableRow/CustomTableRow.js" rel="noopener noreferrer"&gt;CustomTableRow&lt;/a&gt;, &lt;a href="https://github.com/the22mastermind/gourmet-admin/blob/main/src/components/CustomTableFooter/CustomTableFooter.js" rel="noopener noreferrer"&gt;CustomTableFooter&lt;/a&gt;, and &lt;a href="https://github.com/the22mastermind/gourmet-admin/blob/main/src/components/TablePaginationActions/TablePaginationActions.js" rel="noopener noreferrer"&gt;TablePaginationActions&lt;/a&gt; and the result will look like the image below:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbhidbuveq5hudxv7ik2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbhidbuveq5hudxv7ik2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it, the admin will now be able to view and update orders.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;em&gt;There are lots of features we can add to improve our app. For instance, the first page of the dashboard could contain a summary or an overview of the data in our app like the number of orders for a given period of time, the amount of profit made, the most bought items, etc. We could also leverage the power of websockets to make our app show real-time data or add notifications for when an order is placed or any other action.&lt;/em&gt;&lt;br&gt;&lt;/p&gt;



&lt;p&gt;This concludes our series.&lt;/p&gt;



&lt;p&gt;To recap, we've built a REST API using Node, Express, and Postgres then we built frontend apps in React and React-Native to use the API. We've also covered JWT authentication, unit, integration, and end-to-end testing along with continuous integration and continuous delivery (CI/CD).&lt;br&gt;&lt;/p&gt;



&lt;p&gt;I hope this series was useful to you. If you have a question, a comment, or a suggestion let me know in the comment box below.&lt;br&gt;&lt;/p&gt;



&lt;p&gt;Thank you for your time, until next time, cheers!&lt;br&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (7)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Fri, 05 Mar 2021 18:38:52 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-7-5ka</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-7-5ka</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Hi, Welcome to part 7 of this series.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Today, we are going to implement authentication on our front-end apps.&lt;br&gt;&lt;br&gt;
We are going to start with the admin web app then proceed with the mobile app.&lt;br&gt;&lt;br&gt;&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project Steps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;1. Backend - Project Setup&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;2. Backend - Authentication - Sign Up&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;3. Backend - Authentication - Login &amp;amp; Logout&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5"&gt;4. Backend - Place Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-5-24gg"&gt;5. Backend - View Orders List &amp;amp; View a Specific Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;6. Backend - Update Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;7. Front-end - Authentication&lt;/a&gt; 📌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;8. Front-end - Place Order, View Orders List, and View Order Details&lt;/a&gt; 🔥&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;br&gt;&lt;br&gt;
Let us begin with the admin web app &lt;code&gt;(gourmet-admin)&lt;/code&gt;.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Make sure the main branch is up to date with the remote main branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;ft-authentication&lt;/code&gt; branch off the main branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your terminal, run the following command to install the packages we are going to be using:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @material-ui/core @material-ui/icons @material-ui/lab axios cross-env history parcel parcel-bundler react-hook-form react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install dev-dependencies:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D axios-mock-adapter @babel/core @babel/preset-env @babel/preset-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src&lt;/code&gt; directory create the following directories: &lt;code&gt;components, context, navigation, pages, and utils&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/components&lt;/code&gt; directory create the following directories: &lt;code&gt;CustomDrawer, FormButton, FormInput, Loader, Title, and ToastNotification&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have seen a lot of people who like to put their test files in a separate &lt;code&gt;__tests__&lt;/code&gt; directory in the project root and it is totally fine. For me though, I like it when a test file is right next to the component it is supposed to test. I think it makes more sense this way.&lt;br&gt;&lt;br&gt;
That being said, we are going to be creating a component with its test file in the same directory.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's start with a title component that we will use throughout our app to display page titles or headings.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/components/Title&lt;/code&gt; create two files: &lt;code&gt;Title.js&lt;/code&gt; and &lt;code&gt;Title.test.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;Title.js&lt;/code&gt; paste the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxo21pr557eyr1prq8bhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxo21pr557eyr1prq8bhz.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;Title.test.js&lt;/code&gt; paste the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fageh3h33u9y59gvt6821.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fageh3h33u9y59gvt6821.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not pay attention to that import of render and screen on the second line for now. We will implement &lt;code&gt;src/customRender.js&lt;/code&gt; before running our tests.&lt;br&gt;&lt;br&gt;
Cool!&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement the remaining components like &lt;a href="https://github.com/the22mastermind/gourmet-admin/tree/ft-authentication/src/components" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us now create a reducer that we will use to update our authentication state.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/context/reducers/authReducer.js&lt;/code&gt; and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzhcj7ul3kx1axyujnmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzhcj7ul3kx1axyujnmt.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/contenxt/AuthState.js&lt;/code&gt; and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6kzz7l4bakox4fypai5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6kzz7l4bakox4fypai5.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/utils/history.js&lt;/code&gt; and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1tnwg2ntyfbidghg6m8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1tnwg2ntyfbidghg6m8.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/context/theme.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr71ivad8xx6pghp39oab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr71ivad8xx6pghp39oab.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before creating the navigation of our app, let us create the three pages we will need for the authentication feature namely &lt;code&gt;LoginPage&lt;/code&gt;, &lt;code&gt;Dashboard&lt;/code&gt;, and &lt;code&gt;NotFound&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/pages&lt;/code&gt; create the following directories: &lt;code&gt;Dashboard&lt;/code&gt;, &lt;code&gt;LoginPage&lt;/code&gt;, and &lt;code&gt;NotFound&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/pages/NotFound/NotFound.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rvnnlyhi2mcmnc9lwf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rvnnlyhi2mcmnc9lwf0.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/pages/Dashboard/index.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05oebga13dxw60vp6ocp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05oebga13dxw60vp6ocp.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/pages/LoginPage/LoginPage.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg6ig1t1c04toi268nau.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg6ig1t1c04toi268nau.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/utils/validations.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54urb58siv1btq0se3dv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54urb58siv1btq0se3dv.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/utils/api.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F798bebcg819a1mo9n2mi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F798bebcg819a1mo9n2mi.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can create our routes and app navigation.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;What we want to achieve is when a user (admin) visits our web app, he will land on our login page then when he logs in, he will be redirected to the dashboard.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let us implement a wrapper route that we will use to render protected routes like the dashboard.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/navigation/ProtectedRoute.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwsqx9jborei6mw7q0rp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwsqx9jborei6mw7q0rp.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/navigation/Routes.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ettw00vn15sgwgfrnl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ettw00vn15sgwgfrnl0.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need to wrap our routes with our AuthProvider so that our components can have access to our state and ThemeProvider to be able to use Material UI components.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/navigation/index.js&lt;/code&gt; file and paste the following inside:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry8cpt7w9fgi5oi41lek.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we just need to hook this Providers component in our main App and we are good to go.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/App.js&lt;/code&gt; to look like the following:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp6wpi6gatie0b9i9bhck.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us now update our scripts in &lt;code&gt;package.json&lt;/code&gt; and launch our app.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;scripts&lt;/code&gt; to look like the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd9f757emzjm8jm8yfpb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd9f757emzjm8jm8yfpb.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;public/index.html&lt;/code&gt; to look like the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98js9xy69l4lhssqtcyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98js9xy69l4lhssqtcyc.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now run &lt;code&gt;yarn start --open&lt;/code&gt; to tell Parcel to build our app and launch it at &lt;code&gt;http://localhost:1234&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the app launches it should look like the image below:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbf5gvikjb99gh4a5x518.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbf5gvikjb99gh4a5x518.png" alt="localhost_1234_(Laptop with HiDPI screen)"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Great!&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let us now take care of our tests.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;scripts&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt; to look like the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywazdlkp5rhht61d8x50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywazdlkp5rhht61d8x50.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/customRender.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpzdf76t61hf5xc3cv45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpzdf76t61hf5xc3cv45.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learn more about how this file is useful &lt;a href="https://testing-library.com/docs/react-testing-library/setup" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/pages/LoginPage.test.js&lt;/code&gt; and paste the following inside:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdrsv7jpjhsm590ny09u8.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this file we are testing if the page renders correctly, validation errors then we mock HTTP requests to our API to test scenarios such as when there is a network issue, when the user trying to login does not exist or when the user exists but he/she is not an admin and finally we test a successful login.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;yarn test&lt;/code&gt; to run the unit and integration tests with Jest. When the test runner finishes you should see each test file's status and the test coverage.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the moment I have 96% coverage which is not bad. You could use the coverage table to investigate the uncovered lines and write either unit tests or integration tests to cover them and increase coverage.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Now we can commit our changes to GitHub and open a PR to trigger a build on CircleCI.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If all goes well, go ahead and merge the PR and we can proceed with the mobile app.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For reference, check out this &lt;a href="https://github.com/the22mastermind/gourmet-admin/tree/ft-authentication" rel="noopener noreferrer"&gt;branch&lt;/a&gt;&lt;br&gt;&lt;/p&gt;




&lt;p&gt;For our mobile app we need to implement sign up on top of login and logout.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's do it.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Switch to the &lt;code&gt;Gourmet&lt;/code&gt; project directory that we created in the previous post and make sure the main branch is up to date with its remote&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;ft-authentication&lt;/code&gt; branch off the main branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install dependencies by running:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @react-native-async-storage/async-storage @react-navigation/native @react-navigation/stack @react-native-community/masked-view react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens react-native-paper react-native-vector-icons react-hook-form axios prop-types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install additional dev-dependencies:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D axios-mock-adapter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src&lt;/code&gt; create the following directories: &lt;code&gt;components, context, navigation, screens, and utils&lt;/code&gt; and in each directory create a component file and its test file like &lt;a href="https://github.com/the22mastermind/gourmet/tree/ft-authentication/src/components" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/utils/storage.js&lt;/code&gt; file and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i7g50nk3w2jwewbeh8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i7g50nk3w2jwewbeh8j.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This code will help us to interact with the storage by using the &lt;a href="https://react-native-async-storage.github.io/async-storage/docs/usage" rel="noopener noreferrer"&gt;AsyncStorage&lt;/a&gt; package to create, fetch, and delete data.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/utils/validations.js&lt;/code&gt; and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfdni0ex4t1pje0qnanp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfdni0ex4t1pje0qnanp.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/utils/api.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4ybt9hbem1iwngucs4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc4ybt9hbem1iwngucs4s.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us now create our context providers and consumers.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a new directory &lt;code&gt;reducers&lt;/code&gt; in &lt;code&gt;src/context/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/context/reducers/AuthReducer.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafq02mzx8bqg3k7h5odt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafq02mzx8bqg3k7h5odt.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/context/reducers/AlertReducer.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4kv23mh7ckv4dpks4ie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz4kv23mh7ckv4dpks4ie.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/context/AuthProvider.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mcw51fi5f51ddw4ezhi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mcw51fi5f51ddw4ezhi.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/context/AlertProvider.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3bj0on51btpiu6n589f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3bj0on51btpiu6n589f.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/context/theme.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj4s0po06lk9un7rb8tj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj4s0po06lk9un7rb8tj.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can create the first screens of our app. We are going to create a &lt;code&gt;signup screen, verify screen, login screen, and home screen&lt;/code&gt;. The &lt;code&gt;home screen&lt;/code&gt; will only be visible to logged in users. Let us first create the screens then we can separate them in &lt;code&gt;AustStack&lt;/code&gt; and &lt;code&gt;HomeStack&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens&lt;/code&gt; create the following directories: &lt;code&gt;HomeScreen&lt;/code&gt;, &lt;code&gt;LoginScreen&lt;/code&gt;, &lt;code&gt;SignupScreen&lt;/code&gt;, and &lt;code&gt;VerifyScreen&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/SignupScreen&lt;/code&gt; create two files: &lt;code&gt;SignupScreen.js&lt;/code&gt; and &lt;code&gt;SignupScreen.test.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/SignupScreen/SignupScreen.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7eku6hhzfj9put9c2ffp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7eku6hhzfj9put9c2ffp.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/SignupScreen/SignupScreen.test.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmkufymrobr3ulvrzy87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmkufymrobr3ulvrzy87.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/VerifyScreen&lt;/code&gt; create two files: &lt;code&gt;VerifyScreen.js&lt;/code&gt; and &lt;code&gt;VerifyScreen.test.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/VerifyScreen/VerifyScreen.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmpph8cu9a022ax2kevu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmpph8cu9a022ax2kevu.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/VerifyScreen/VerifyScreen.test.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsebtm62yvhvri7ztpymu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsebtm62yvhvri7ztpymu.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/LoginScreen&lt;/code&gt; create two files: &lt;code&gt;LoginScreen.js&lt;/code&gt; and &lt;code&gt;LoginScreen.test.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/LoginScreen/LoginScreen.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a9v8r2aqtqq8d71ake4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a9v8r2aqtqq8d71ake4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/LoginScreen/LoginScreen.test.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02m8usgjvean0dcehe3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02m8usgjvean0dcehe3g.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/HomeScreen&lt;/code&gt; create two files: &lt;code&gt;HomeScreen.js&lt;/code&gt; and &lt;code&gt;HomeScreen.test.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/HomeScreen/HomeScreen.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg434vocmlkgu5vschsog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg434vocmlkgu5vschsog.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inside &lt;code&gt;src/screens/HomeScreen/HomeScreen.test.js&lt;/code&gt; paste the following code:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyk8rxu8orirqlkvn5za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyk8rxu8orirqlkvn5za.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/navigation/AuthStack.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5aa77bgomdhrfux65trh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5aa77bgomdhrfux65trh.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/navigation/HomeStack.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ynrxgwummwdnegswnu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ynrxgwummwdnegswnu8.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/navigation/Routes.js&lt;/code&gt; file and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x6yul2qln6a8o0f9at4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x6yul2qln6a8o0f9at4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;code&gt;src/navigation/__tests__&lt;/code&gt; directory and inside create a &lt;code&gt;Routes.test.js&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0la24dasmdmg8bjxlfd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0la24dasmdmg8bjxlfd6.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let us wrap our routes with the providers we created earlier and the React-Native-Paper provider.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/App.js&lt;/code&gt; file to look like the following:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4ajh3nergz5lc6qz1by.png" alt="image"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we were to run our tests they would fail because we haven't yet wrapped our providers around components and screens in the test environment. To do so, update &lt;code&gt;test-utils.js&lt;/code&gt; to look like the following:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqedszpw5bj5rf5zfnfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqedszpw5bj5rf5zfnfb.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now run the tests again and they should pass.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If you get errors make sure &lt;code&gt;jest.config.js, jest.setup.js, and setupFiles.js&lt;/code&gt; look like below and run tests again:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf9tz5r3lc4u0a09yfmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf9tz5r3lc4u0a09yfmv.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, you can run the app on your emulator or physical device to test that everything works as it should.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;That's it for today! Push the authentication branch to GitHub, open a PR, wait for the &lt;code&gt;Continuous Integration&lt;/code&gt; workflow to succeed then merge the PR.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For reference, check out &lt;a href="https://github.com/the22mastermind/gourmet" rel="noopener noreferrer"&gt;this branch&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In the next post, we will wrap up this series with the following features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Place order (mobile app)&lt;/li&gt;
&lt;li&gt;View orders list (mobile app and admin web app)&lt;/li&gt;
&lt;li&gt;View single order details (mobile app and admin web app)
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thank you for your time. See you in the next post!&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (6)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Thu, 04 Mar 2021 21:08:36 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-6-467e</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-6-467e</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Hi, Welcome to part 6 of this series.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Today, we are going to wrap up the backend of our app &lt;em&gt;"Gourmet"&lt;/em&gt; by implementing the functionality that allows the admin to update the status of an order placed by a customer.&lt;br&gt;&lt;br&gt;
We are also going to set up our front-end client apps namely the web app for the admin and the mobile app for customers.&lt;br&gt;&lt;br&gt;&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project Steps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;1. Backend - Project Setup&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;2. Backend - Authentication - Sign Up&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;3. Backend - Authentication - Login &amp;amp; Logout&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5"&gt;4. Backend - Place Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-5-24gg"&gt;5. Backend - View Orders List &amp;amp; View a Specific Order&lt;/a&gt; ✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;6. Backend - Update Order&lt;/a&gt; 📌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=""&gt;7. Front-end - Authentication&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href=""&gt;8. Front-end - Place Order, View Orders List, and View Order Details&lt;/a&gt; 🔥&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;br&gt;&lt;br&gt;
Let us begin by writing our tests.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the main branch is up to date with the remote main branch&lt;/li&gt;
&lt;li&gt;Create a new &lt;code&gt;ft-admin-update-order&lt;/code&gt; branch off our main branch&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;tests/orders.test.js&lt;/code&gt; and add the following &lt;code&gt;ADMIN UPDATE ORDER&lt;/code&gt; test suite along with the new messages. Dont' forget the &lt;code&gt;conflict&lt;/code&gt; status code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqHWGO-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2xhtsoqboorekt6i5dht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqHWGO-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2xhtsoqboorekt6i5dht.png" alt="carbon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/utils/messages.js&lt;/code&gt; and add the new messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p9fqU56m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/avvn7pdtypf2ri88ym21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p9fqU56m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/avvn7pdtypf2ri88ym21.png" alt="carbon (1)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/validations/orders.js&lt;/code&gt; and add the &lt;code&gt;updateOrder&lt;/code&gt; function which will help us to validate the status.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CQtSOLiv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y7vap1581y2ansurxmih.png" alt="carbon (2)"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;accepted&lt;/code&gt;, &lt;code&gt;onthemove&lt;/code&gt;, and &lt;code&gt;completed&lt;/code&gt; are the only allowed values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/orders.js&lt;/code&gt; and add the &lt;code&gt;validateUpdateOrder&lt;/code&gt; function and &lt;code&gt;checkOrderStatus&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EFkF102x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6dknyiiwypw39bxw4olq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EFkF102x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6dknyiiwypw39bxw4olq.png" alt="carbon (3)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;checkOrderStatus&lt;/code&gt; function will help us to avoid updating an order status to a value that it already has thus saving up a bit on our server resources. For example, if the admin has already accepted an order, there's no point of accepting it again.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/orders.js&lt;/code&gt; and add the &lt;code&gt;updateOrder&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5rucwxQQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/utdocolew3oflgd72ogx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5rucwxQQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/utdocolew3oflgd72ogx.png" alt="carbon (4)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, update &lt;code&gt;src/routes/adminRoutes.js&lt;/code&gt; and add the update order route. The final &lt;code&gt;adminRoutes.js&lt;/code&gt; file should look like the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4VzJSIrH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zqlxtma44a8eyz0wtk6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4VzJSIrH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zqlxtma44a8eyz0wtk6d.png" alt="carbon (5)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
And that's it!&lt;br&gt;&lt;/p&gt;

&lt;p&gt;If you run the tests again, they should all pass which means everything is working as it should.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Now, go ahead and commit the new changes to GitHub and open a PR. After a successful Travis build, merge the PR to trigger a new production build on Heroku.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; There's a bug I caught on signup. Check out the fix on this &lt;a href="https://github.com/the22mastermind/gourmet-api/pull/11"&gt;PR&lt;/a&gt; if you had not caught it.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Our simple backend is now done. Let us now set up the front-end client apps.&lt;br&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Admin Panel React App
&lt;/h2&gt;

&lt;p&gt;This web app will help the admin of &lt;code&gt;Gourmet&lt;/code&gt; restaurant to manage the orders of customers.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For now, the admin will be able to fetch all the orders, fetch a single order details, and update an order's status to let the customer know the progress of their order.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Later on, we could add more features like user management, staff management, analytics, inventory management and any other feature that would improve the processes of Gourmet as a business.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;We are going to deploy this admin web app to &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;, but you could use any other cloud service.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Going forward, I assume you are familiar with React. If not, check out &lt;a href="https://reactjs.org/"&gt;React Offical Docs&lt;/a&gt; and &lt;a href="https://create-react-app.dev/docs/getting-started/"&gt;Create React App&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using &lt;a href="https://create-react-app.dev/docs/getting-started/"&gt;Create React App&lt;/a&gt;, create a new React app called &lt;code&gt;gourmet-admin&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When done, follow the instructions on your terminal to launch your new app in the browser&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install and configure React Testing Library. More info &lt;a href="https://testing-library.com/docs/"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Refactor &lt;code&gt;App.js&lt;/code&gt; to remove unnecessary boilerplate code and &lt;code&gt;App.test.js&lt;/code&gt; to use React Testing Library then run &lt;code&gt;yarn test&lt;/code&gt; to make sure the tests are passing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the project to a new GitHub repo, setup CircleCI and &lt;a href="https://www.netlify.com/blog/2016/07/22/deploy-react-apps-in-less-than-30-seconds/"&gt;Netlify&lt;/a&gt; as our CI and CD respectively&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure test coverage with both coveralls and CodeCov&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes to GitHub, open a PR to trigger a build job on CircleCI to run our tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the build is successful, go ahead and merge the PR to trigger a new deploy build on Netlify.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is going to be our workflow for the admin app going forward.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For reference, check out &lt;a href="https://github.com/the22mastermind/gourmet-admin/tree/ch-circleci-config-fix"&gt;this branch&lt;/a&gt;&lt;br&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Customer React Native App
&lt;/h2&gt;




&lt;p&gt;This mobile app will help customers to view the restaurant's menu and to place orders.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;We are going to build a very simple Android React Native app but if you want an IOS version as well, it is fairly simple to configure it.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you are not familiar with React Native, follow this &lt;a href="https://reactnative.dev/docs/getting-started"&gt;offical guide&lt;/a&gt; to learn how to setup the dev environment and core concepts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;React Native CLI&lt;/code&gt;, create a new React Native App called &lt;code&gt;Gourmet&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure you can launch it on an emulator or a physical device&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure ESLint, Jest, and setup React Native Testing Library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove unnecessary boilerplate code from &lt;code&gt;App.js&lt;/code&gt;, refactor &lt;code&gt;App.test.js&lt;/code&gt;, and run tests to make sure they are passing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the project to a new repo on GitHub, setup CodeCov, and GitHub actions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes to GitHub, open a PR, wait for the workflow to succeed then merge the PR&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For reference, check out &lt;a href="https://github.com/the22mastermind/gourmet/tree/ch-project-setup"&gt;this branch&lt;/a&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;The basic implementation for our front-end apps is done. In the next post we will implement authentication in the following manner:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login and logout on the admin app.&lt;/li&gt;
&lt;li&gt;Sign up, login, and logout on the mobile app.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thank your for reading, see you in the next one!&lt;br&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (5)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Tue, 26 Jan 2021 12:39:07 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-5-24gg</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-5-24gg</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Hi, Welcome back to part 5 of this series.&lt;br&gt;&lt;br&gt;
In today's post we are going to implement the functionality that allows a customer to view an order they have placed and for the admin to view a list of orders placed by customers as well as a specific order's details.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;Backend - Project Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Backend - Authentication

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;Backend - Authentication - Signup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;Backend - Authentication - Login and Logout&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5"&gt;Backend - Place order&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=""&gt;Backend - View orders list and view a specific order&lt;/a&gt; 📌&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;Backend - Update order&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;Frontend - Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;Frontend - Place order, view orders list, and view order details&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Let us begin by implementing the functionality to fetch an order by it's id from the perspective of a customer. We are going to add checks to verify if the id submitted is valid, if the order it refers to exists, and finally, if the user who is making this request is the one who placed that order.&lt;br&gt;&lt;br&gt;
Later on, we could build on top of this functionality to add features such as &lt;code&gt;Quick re-order&lt;/code&gt; and &lt;code&gt;Order live-tracking&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/utils/messages.js&lt;/code&gt; and add the following new messages:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TKMea78S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5uzuvu672x4lup8n1emu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TKMea78S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5uzuvu672x4lup8n1emu.png" alt="carbon (1)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;tests/orders.test.js&lt;/code&gt; and add the &lt;code&gt;customer get order&lt;/code&gt; test suite:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4vciL_Aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8qtfu2tyjkel2awonunw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4vciL_Aa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8qtfu2tyjkel2awonunw.png" alt="carbon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last two test cases we placed a new order, then we try to fetch it by it's id. We are also checking to see if the data object in the returned response has all the information related to that order, like its contents, and the details of the user who placed the order.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/validations/orders.js&lt;/code&gt; and add the &lt;code&gt;getOrder&lt;/code&gt; function which will help us to validate the order id:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IY_lo_wM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mdly1kl6wqso66qt5zq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IY_lo_wM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mdly1kl6wqso66qt5zq2.png" alt="carbon (2)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/services/services.js&lt;/code&gt; and add the &lt;code&gt;findOrderByConditionAll&lt;/code&gt; function that will help us to find an order given certain conditions. In this case, we want to find an order given it's id and the id of the user who placed it.
Sequelize allows us to use logical operators to filter queries as you would with normal SQL queries. Learn more &lt;a href="https://sequelize.org/master/manual/model-querying-basics.html#applying-where-clauses"&gt;here&lt;/a&gt;.
We can even go as far as fetching associated models provided that we have made these associations before. In our case, we want to fetch the order's contents and the details of the user who placed it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7Im8oI1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pbn8aslw1kp9trkc51cx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Im8oI1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pbn8aslw1kp9trkc51cx.png" alt="carbon (3)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note how we included the entire model of Contents and how we selected only the relevant fields that we want on the User model.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/orders.js&lt;/code&gt; and add the &lt;code&gt;validateGetOrder&lt;/code&gt; and &lt;code&gt;findUserOrderById&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MoBmR1WN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u01ffbnwogu9pt1n6ihb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MoBmR1WN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u01ffbnwogu9pt1n6ihb.png" alt="carbon (4)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;validateGetOrder&lt;/code&gt; will help us to use our &lt;code&gt;getOrder&lt;/code&gt; validation function.&lt;br&gt;&lt;br&gt;
Note how instead of passing &lt;code&gt;req.body&lt;/code&gt; to getOrder as a parameter, we pass &lt;code&gt;req.params&lt;/code&gt;. This is because the id we want to validate will not be generated by the user, instead it will be mapped to our route. This means that, given a route &lt;code&gt;/orders/:id&lt;/code&gt;, the id property is available as &lt;code&gt;req.params.id&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;findUserOrderById&lt;/code&gt; we destructure that id from params then create a userId variable from req.userData (this is the id of the user who's making this request). Then we use id from params and userId to put together our condition object which we use in the &lt;code&gt;findOrderByConditionAll&lt;/code&gt; service.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/orders.js&lt;/code&gt; and add &lt;code&gt;getSpecificOrder&lt;/code&gt; method:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T9LUTsGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ao7xe3a3hta8rq7hwmh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T9LUTsGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ao7xe3a3hta8rq7hwmh1.png" alt="carbon (5)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/routes/ordersRoutes.js&lt;/code&gt; to look like the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e8LjfXOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v3354drsmc7k20hp0q1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e8LjfXOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v3354drsmc7k20hp0q1t.png" alt="carbon (6)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;Now run the tests and they should all pass.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;So far a customer can place an order and she can view that order's details.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's now see how fetching orders looks like from the perspective of the admin.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;For the admin, we will create a new route path where all the admin related sub routes will go. This means that in our route index file we will have 3 parent routes: &lt;code&gt;/api/auth&lt;/code&gt;, &lt;code&gt;/api/orders&lt;/code&gt;, and &lt;code&gt;/api/admin&lt;/code&gt;.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;But before we create the routes, let us write our tests.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;tests/orders.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VYNTFME0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yu3kfr9w06e412wroeg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VYNTFME0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yu3kfr9w06e412wroeg5.png" alt="carbon (7)"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Note how we added our new tests suite before and after &lt;code&gt;CUSTOMER PLACE ORDER&lt;/code&gt; and &lt;code&gt;CUSTOMER GET ORDER&lt;/code&gt; suites. This allows us to test the Not Found or Empty scenario and the Success scenario respectively.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;In short, we are testing the absence of something, then create something, and finally test the presence of that thing. Does it make sense?&lt;br&gt;&lt;br&gt;
This is one way to do it though.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let us now create a service that will allow the admin to fetch all the orders placed by customers, starting with the most recently placed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b_5RF4Tb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98zb9iwdrfwceonre4tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b_5RF4Tb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98zb9iwdrfwceonre4tu.png" alt="carbon (8)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/orders.js&lt;/code&gt; and add the &lt;code&gt;findOrderById&lt;/code&gt; and &lt;code&gt;findOrdersList&lt;/code&gt; functions:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lqjqNpy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dlm0qanzegwwynie4k0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lqjqNpy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dlm0qanzegwwynie4k0i.png" alt="carbon (10)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make sure the middlewares we just created are only accessible to the admin, we need to create  another middleware that checks the role of the user who is making  the request and then grants access or not.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/authentication.js&lt;/code&gt; and add the &lt;code&gt;checkAdminRole&lt;/code&gt; function:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6-2TaH0r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nblrvwvie9gtjhwwo8iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6-2TaH0r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nblrvwvie9gtjhwwo8iw.png" alt="carbon (11)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/orders.js&lt;/code&gt; and add the &lt;code&gt;getOrdersList&lt;/code&gt; method:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rh-x641_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rlnoz3txata3ggt1jglr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rh-x641_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rlnoz3txata3ggt1jglr.png" alt="carbon (12)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let us create the admin sub routes and include them in the main routes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new &lt;code&gt;src/routes/adminRoutes.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XvIgywwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3xqwdr8q2sujafei8jsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XvIgywwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3xqwdr8q2sujafei8jsa.png" alt="carbon (13)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, update &lt;code&gt;src/routes/index.js&lt;/code&gt; and include the admin routes:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1cyekIbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/72wpyunatmbiim4vv0xb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1cyekIbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/72wpyunatmbiim4vv0xb.png" alt="carbon (14)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Now run the tests and they should all pass.&lt;br&gt;&lt;br&gt;
Now we can commit our changes to GitHub, open a PR, wait for Travis to successfully build then merge the PR to trigger a new production build.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Thank you for following this series.&lt;br&gt;&lt;br&gt;
In the next post, we are going to wrap up our API with the functionality that allows the admin to update the status of an order.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
The code in this post can be found &lt;a href="https://github.com/the22mastermind/gourmet-api"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
See you in the next one!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (4)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Sun, 24 Jan 2021 19:47:14 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Hi, Welcome back!&lt;br&gt;&lt;br&gt;&lt;br&gt;
In today's post we are going to implement the place order functionality, the admin account, and a sample version of our restaurant's menu. At the end of this post, a customer should be able to successfully place an order.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;Backend - Project Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Backend - Authentication

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;Backend - Authentication - Signup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;Backend - Authentication - Login and Logout&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href=""&gt;Backend - Place order&lt;/a&gt; 📌&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - View orders list and view a specific order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - Update order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Authentication&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Place order, view orders list, and view order details&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Let's begin with creating the admin account. The admin account will have access to functionalities such as accepting orders placed by customers, blacklisting/whitelisting users, creating staff accounts, and creating menus among other things. Since this account will have access to sensitive information, we cannot just create an endpoint for it. We need to create a script that will create this account by skipping the signup process.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;We also need a way to differentiate the users of our app by their roles namely &lt;strong&gt;customer&lt;/strong&gt;, &lt;strong&gt;admin&lt;/strong&gt;, and &lt;strong&gt;staff&lt;/strong&gt;.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Customer&lt;/strong&gt; refers to a user who will download our app from the Google play store to place orders.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin&lt;/strong&gt; refers to the owner or manager of Gourmet restaurant. He/she should be able to create menus of dishes, create and remove staff accounts, and manage orders.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Staff&lt;/strong&gt; refers to an employee in the restaurant who will be created by the admin or manager. In case the manager is not there, the staff account should also be able to manage orders as the staff on duty.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's begin by creating the roles. We will need to modify a little bit the sign up process we created in the previous posts to make sure a user who signs up is identified as a customer by default.&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a new branch called &lt;code&gt;ft-place-order&lt;/code&gt; off our main branch.&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;src/utils/roles.js&lt;/code&gt; file and paste the following code inside:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;Valid signup should return 201&lt;/code&gt; test case in &lt;code&gt;test/authentication.js&lt;/code&gt; to check if a signed-up user is a customer like this:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;Valid login should return 200&lt;/code&gt; test case in &lt;code&gt;test/authentication_login.js&lt;/code&gt; to check if a logged-in user is a customer like this:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/User.js&lt;/code&gt; and add the role field like this:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Create a new migration to add the role field on the User model by running the following command in your terminal &lt;code&gt;npx sequelize-cli migration:generate --name add-role-to-user&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/migrations/**-add-role-to-user.js&lt;/code&gt; file to look like this:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; to add the role of &lt;strong&gt;customer&lt;/strong&gt; on sign up like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now run your tests and they should all pass. If you were to inspect the user created in the database, you should see that the user has a role of &lt;strong&gt;customer&lt;/strong&gt;. This means that every user who signs up will be given a role of customer automatically. Awesome!&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Admin account&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Let's now create our admin account starting with the tests.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;tests/authentication_admin.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In the test case above we are checking if given the correct admin credentials, the admin can login successfully.&lt;br&gt;&lt;br&gt;
At this point this test case should fail because we haven't yet created the admin account.&lt;br&gt;&lt;br&gt;
Let's now create a script that will create the admin account and make the test case above pass.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/database/scripts/adminScript.js&lt;/code&gt; file and paste the following code inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In the code above we created a function called &lt;code&gt;createAdmin&lt;/code&gt; that will first hash our plain-text admin password then call the &lt;code&gt;findOrCreate&lt;/code&gt; method on the User model. &lt;code&gt;findOrCreate&lt;/code&gt; method as the name suggests will first try to find if a record exists in the database, if it is found it will return its instance, if it doesn't exist then it creates a new record. we used this method because we want to be running our script automatically after each production build. If we were to use the &lt;code&gt;create&lt;/code&gt; method, it would create the record the first time but would throw an error the second time as we would be trying to create a record that already exists.&lt;br&gt;&lt;br&gt;
Lastly we call &lt;code&gt;createAdmin&lt;/code&gt; function and export it so that when we will execute this file, it will call this createAdmin function. Cool!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;.env&lt;/code&gt; file and add the &lt;code&gt;ADMIN_PHONE&lt;/code&gt; and &lt;code&gt;ADMIN_PASSWORD&lt;/code&gt; environment variables.

Let's now create a command to run our script.

&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;package.json&lt;/code&gt; and include the script to create the admin account in &lt;code&gt;pretest&lt;/code&gt; and &lt;code&gt;heroku-postbuild&lt;/code&gt; commands. This way our admin account will be created before running our tests and after the production build respectively.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now run your tests again and they should all pass. Great!&lt;br&gt;
&lt;br&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Place order&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
At this point we need to start thinking about what kind of information we should show to customers and what information to expect when they place orders. &lt;br&gt;&lt;br&gt;
We are going to create 4 additional models namely: Menu, Item, Order, and Contents.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Menu&lt;/strong&gt; will refer to a category such as Breakfast, Lunch, Dinner, Drinks, etc.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Item&lt;/strong&gt; will refer to the actual dish or drink such as Cheese Burger, Coke Diet, Orange Juice, etc.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Order&lt;/strong&gt; will refer to the orders placed by customers and will contain details such as the total amount, order status, user Id, etc.&lt;br&gt;&lt;br&gt;
Lastly, &lt;strong&gt;Contents&lt;/strong&gt; will contain each item details for a specific order.&lt;br&gt;&lt;br&gt;
Regarding model relations or associations, we need to link Order model with User model by adding a foreign key of userId to the Order model. We also need to link Order model with Contents model by adding a foreign key of orderId to the Contents model. And lastly we need to link Menu model with Item model by adding a foreign key of MenuId to the Item model.&lt;br&gt;&lt;br&gt;
Great! Now that we have an idea of the structure of our new models and associations, let's start implementing the place order feature.&lt;br&gt;&lt;br&gt;
As always, we will begin by writing our tests.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;tests/orders.test.js&lt;/code&gt; file and paste the following code:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/utils/messages.js&lt;/code&gt; and add the new messages:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Create a new model called &lt;strong&gt;Menu&lt;/strong&gt; with the following command &lt;code&gt;npx sequelize-cli model:generate --name Menu --attributes name:string&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Create another model called &lt;strong&gt;Item&lt;/strong&gt; with &lt;code&gt;npx sequelize-cli model:generate --name Item --attributes name:string,description:string,cost:decimal,size:string,image:string&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Create a new migration to add the menuId field to our Item model by running &lt;code&gt;npx sequelize-cli migration:generate --name add-menuId-to-item&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/migrations/**-add-menuId-to-item.js&lt;/code&gt; migration to look like the following:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/item.js&lt;/code&gt; to add the relation/association between &lt;code&gt;Item&lt;/code&gt; and &lt;code&gt;Menu&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/menu.js&lt;/code&gt; to add the One-to-many association between &lt;code&gt;Item&lt;/code&gt; and &lt;code&gt;Menu&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Create another model called &lt;strong&gt;Order&lt;/strong&gt; with &lt;code&gt;npx sequelize-cli model:generate --name Order --attributes total:decimal,status:string,paymentId:string&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Create another model called &lt;strong&gt;Contents&lt;/strong&gt; with &lt;code&gt;npx sequelize-cli model:generate --name Contents --attributes itemId:integer,itemName:string,cost:decimal,quantity:integer&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Create a new migration to add the orderId field to our Contents model by running &lt;code&gt;npx sequelize-cli migration:generate --name add-orderId-to-contents&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/migrations/**-add-orderId-to-contents.js&lt;/code&gt; migration to look like the following:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Create a new migration to add the userId field to our Order model by running &lt;code&gt;npx sequelize-cli migration:generate --name add-userId-to-order&lt;/code&gt;

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/migrations/**-add-userId-to-order.js&lt;/code&gt; migration to look like the following:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/order.js&lt;/code&gt; to add the association between &lt;code&gt;Order&lt;/code&gt; and &lt;code&gt;Contents&lt;/code&gt; and between &lt;code&gt;Order&lt;/code&gt; and &lt;code&gt;User&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/user.js&lt;/code&gt; to add the one-to-many association between &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Order&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Let us now create our validations for place order.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/validations/orders.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Do not forget to export the &lt;code&gt;createErrorMessages&lt;/code&gt; function from &lt;code&gt;src/validations/authentication.js&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new &lt;code&gt;src/middlewares/orders.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Before we create the controller and route for placing orders, let's think about how a customer will place an order.&lt;br&gt;&lt;br&gt;
In the Gourmet mobile app, the customer will be presented with a menu that has a list of items to choose from. When the customer taps on the add button, the item's id, name, cost, and quantity will be added to their cart. Subsequent addition of the same item will increase the item's quantity and cost. On checkout we will use the cart's items to calculate the total amount of the order and when the customer pays for the order, we will include the paymentId for reference.&lt;br&gt;&lt;br&gt;
The following image shows a sample of the request's body which will be send to the server when a customer places an order:&lt;/p&gt;

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

&lt;p&gt;The order is for one double cheese burger and two diet cokes.&lt;br&gt;&lt;br&gt;
The items inside the contents array is what we will save in our Contents model. And if we remember, we defined an association that will ensure an item has an orderId. We need a way to add an orderId to each item in the order's contents.&lt;br&gt;&lt;br&gt;
Let us create a function that will take our contents array and an orderId then add that orderId to each item inside the contents array.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/helpers/misc.js&lt;/code&gt; and add the &lt;code&gt;parseOrderContents&lt;/code&gt; function:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/services/services.js&lt;/code&gt; and add the &lt;code&gt;saveManyRows&lt;/code&gt; function:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The &lt;code&gt;bulkCreate&lt;/code&gt; method unlike &lt;code&gt;create&lt;/code&gt;, allows us to create multiple records at the same time.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
We are now ready to create the controller and use these functions we created above.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new &lt;code&gt;src/controllers/orders.js&lt;/code&gt; file and paste the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In the &lt;code&gt;placeOrder&lt;/code&gt; method we destructure the request's body to reveal total, contents, and paymentId. Then, we create our order Object will will have the total, paymentId, a default status of pending, and the userId. The userId's value is handed to us by the authentication middleware function &lt;code&gt;checkUserToken&lt;/code&gt; through &lt;code&gt;req.userData.id&lt;/code&gt;. we then save our order record then use the returned record's id to add it to each item in the contents array by calling the &lt;code&gt;parseOrderContents&lt;/code&gt; helper function. We then call &lt;code&gt;saveManyRows&lt;/code&gt; function to save each item in the Contents model.&lt;br&gt;&lt;br&gt;
Let us now create the place order route and use the controller we just created.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/routes/ordersRoutes.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Update a &lt;code&gt;src/routes/index.js&lt;/code&gt; file and add the orders router:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Now run your tests and they should all pass.&lt;br&gt;&lt;br&gt;
And if you check the records in Orders and Contents tables in the database, you should see that our data is saved.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Gourmet Menu&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
One way to create the menu of our restaurant would be to create admin endpoints for creating, viewing, updating, and deleting the menu but for the sake of keeping things simple we will not do that. Instead, we are going to create organized data of our menu that we will insert directly in the database (seeds). When we are done with this series you can implement the above endpoints for managing the menu as the admin on your own since we will have covered all the concepts to do it.&lt;br&gt;&lt;br&gt;
Cool, let us create our seeds.&lt;br&gt;&lt;br&gt;
We are going to create a seed for creating 3 menus, namely &lt;strong&gt;Breakfast&lt;/strong&gt;, &lt;strong&gt;Lunch/Dinner&lt;/strong&gt;, and &lt;strong&gt;Drinks&lt;/strong&gt;. We are going to create another seed for creating items in each menu.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npx sequelize-cli seed:generate --name menus&lt;/code&gt; command in your project root

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/seeders/**-menus.js&lt;/code&gt; to look like this:&lt;/li&gt;
&lt;/ul&gt;

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



&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npx sequelize-cli seed:generate --name items&lt;/code&gt; command in your project root

&lt;/li&gt;
&lt;li&gt;Update the newly created &lt;code&gt;src/database/seeders/**-items.js&lt;/code&gt; to look like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now let us update the scripts section in &lt;code&gt;package.json&lt;/code&gt; to create a command that we will use to create the seeds.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update scripts in &lt;code&gt;package.json&lt;/code&gt; to add the &lt;code&gt;seed&lt;/code&gt; command and to include the seed command on the &lt;code&gt;pretest&lt;/code&gt; command:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Now we can add our new environments variables &lt;code&gt;ADMIN_PHONE&lt;/code&gt; and &lt;code&gt;ADMIN_PASSWORD&lt;/code&gt; to Travis and Heroku environments then commit our changes to GitHub, open a PR and merge it as we have done before.&lt;br&gt;&lt;br&gt;&lt;br&gt;
And that's it for today!&lt;br&gt;&lt;br&gt;
In the next post we are going to look at how to fetch the list of orders and how to fetch a specific order's details. We will do this from the perspective of both the admin and the customer.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Thank you for reading!&lt;br&gt;
&lt;br&gt;&lt;br&gt;
See you in the next one!&lt;br&gt;
&lt;br&gt;&lt;br&gt;
The code in this post can be found &lt;a href="https://github.com/the22mastermind/gourmet-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (3)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Thu, 31 Dec 2020 13:43:09 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Welcome back!&lt;/p&gt;

&lt;p&gt;Today we are going to finish implementing authentication for the backend of our app "Gourmet".&lt;/p&gt;

&lt;p&gt;In this post we will implement the &lt;strong&gt;login&lt;/strong&gt; and &lt;strong&gt;logout&lt;/strong&gt; endpoints.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;Backend - Project Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Backend - Authentication

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;Backend - Authentication - Signup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=""&gt;Backend - Authentication - Login and Logout&lt;/a&gt; 📌&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - Place order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - View orders list and view a specific order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - Update order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Authentication&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Place order, view orders list, and view order details&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Login&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a new branch &lt;code&gt;ft-authentication-login&lt;/code&gt; off our &lt;code&gt;main&lt;/code&gt; branch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;src/utils/messages.js&lt;/code&gt; and add the following messages:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;tests/authentication_login.test.js&lt;/code&gt; file and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If you run the tests, all Login tests should fail because we haven't yet implemented this functionality. Let's do it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/helpers/misc.js&lt;/code&gt; like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The &lt;code&gt;isPasswordValid&lt;/code&gt; function will help us in checking if the password submitted by the user equals to the user's password saved in the database by leveraging bcrypt's &lt;code&gt;compare&lt;/code&gt; function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/validations/authentication.js&lt;/code&gt; and the &lt;code&gt;login&lt;/code&gt; function like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/authentication.js&lt;/code&gt; like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The &lt;code&gt;validateLogin&lt;/code&gt; middleware function will help us to validate the login credentials by using our login validation function.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;checkLogin&lt;/code&gt; middleware function will help us to check if the user trying to login exists in our database and if the password provided is valid.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; and add the &lt;code&gt;login&lt;/code&gt; method like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Finally, update &lt;code&gt;src/routes/authRoutes.js&lt;/code&gt; to create the login route and connect our middlewares and controller&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now run the tests again and you should see that all our Login tests are passing. Nice!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Logout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What we want to achieve when a user logs out is to make sure that their JWT token becomes unusable. Since JWT doesn't have a functionality to force a token to expire, we will have to implement a custom solution.&lt;/p&gt;

&lt;p&gt;If you have noticed, we provided a &lt;code&gt;expiresIn: '30d',&lt;/code&gt; option in our &lt;code&gt;generateToken&lt;/code&gt; function. This option controls the lifespan of our token, in our case it's 30 days. This is fine but imagine if a user logs in then logs out right away, this would mean that their token would still be valid for 30 days and if an attacker was to get hold of this token, they would be able to impersonate the original user. Now imagine if a user logs in then logs out again and they do this 5 consecutive times. We now have to deal with 5 unknown but valid tokens. Now imagine 1000 users doing this everyday - It could get out of hand very quickly.&lt;/p&gt;

&lt;p&gt;Even though there's nothing we can do to force a token to expire before its &lt;code&gt;expiresIn&lt;/code&gt; property, we can introduce a way to manage these tokens, especially for users who have logged out of our system.&lt;/p&gt;

&lt;p&gt;Our solution is to store a user's token in a database when they logout. This database will be separate from our main database and ideally it should be very fast to make the writing and retrieving of data fast.&lt;/p&gt;

&lt;p&gt;Redis is an ideal candidate for such a task because of its high performance and very low latency. Learn more about Redis &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-20-04" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's now implement the logout functionality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Download and install Redis and test that it works well with the &lt;code&gt;ping/pong&lt;/code&gt; command&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In our project root, run &lt;code&gt;yarn add redis&lt;/code&gt; to install the Redis Node.js client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update &lt;code&gt;src/utils/messages&lt;/code&gt; and add the following messages:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;tests/authentication_logout.js&lt;/code&gt; file put the following code inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;src/config/redisClient.js&lt;/code&gt; configuration file like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Update the &lt;code&gt;.env&lt;/code&gt; file and a &lt;code&gt;REDIS_URL&lt;/code&gt; variable with a default port like this: &lt;code&gt;REDIS_URL=redis://@127.0.0.1:6379&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using credentials to connect to your Redis server then your URL would be like this: &lt;code&gt;REDIS_URL=redis://USERNAME:PASSWORD@HOST_NAME:PORT_NUMBER&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/middlewares/authentication.js&lt;/code&gt; and refactor &lt;code&gt;checkUserToken&lt;/code&gt; to this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Here we are using the &lt;code&gt;smembers&lt;/code&gt; method of Redis to retrieve all the members/values in a set. This method takes a string key (&lt;code&gt;token&lt;/code&gt;) and a callback which returns an error or an array of values found. Check out &lt;a href="https://redis.io/commands" rel="noopener noreferrer"&gt;this link&lt;/a&gt; for a list of all the commands/methods.&lt;/p&gt;

&lt;p&gt;We then check if our token is in the &lt;code&gt;tokensArray&lt;/code&gt; and return an appropriate error. &lt;code&gt;tokensArray&lt;/code&gt; contains tokens of logged out users that have not yet expired. So to make a user logout, we just have to store their token in this set of key &lt;code&gt;token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's now implement the controller where we will store the user's token in that set.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; to add the &lt;code&gt;logout&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Notice how we use the &lt;code&gt;sadd&lt;/code&gt; method to add our token in a set of key token. When you use the &lt;code&gt;sadd&lt;/code&gt; method, it appends your value to the set if the set exists. If the set doesn't exist it will first create it.&lt;/p&gt;

&lt;p&gt;Cool!&lt;/p&gt;

&lt;p&gt;Let's now create our logout route.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/routes/authRoutes.js&lt;/code&gt; like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Lastly, let's update our Travis config file to tell Travis to install Redis-server before running our tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;.travis.yml&lt;/code&gt; and &lt;code&gt;redis-server&lt;/code&gt; in services like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;If you run the tests again, you should see that all our authentication tests are passing.&lt;/p&gt;

&lt;p&gt;Now we can commit our changes to GitHub and create a PR which will trigger a build on Travis.&lt;/p&gt;

&lt;p&gt;The last step is to provision a Redis database for our production env on heroku. The process is similar to how we added the Postgres database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;code&gt;Resources&lt;/code&gt; tab on heroku and type &lt;code&gt;Heroku Redis&lt;/code&gt; in the Add-ons search bar then select it. If "Heroku Redis" doesn't show up click &lt;a href="https://elements.heroku.com/addons/heroku-redis" rel="noopener noreferrer"&gt;here&lt;/a&gt; to find it in the market place then click on the install button and confirm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: You might be asked to add a credit card but make sure sure to select the &lt;code&gt;Hobby-dev&lt;/code&gt; plan so that they don't charge you for usage. You can always upgrade to a paid plan after you have tested that everything is working well.&lt;/p&gt;

&lt;p&gt;If the provision of Heroku Redis is successful, it will automatically add a &lt;code&gt;REDIS_URL&lt;/code&gt; env variable.&lt;/p&gt;

&lt;p&gt;Now you can head back to GitHub and merge our PR.&lt;/p&gt;

&lt;p&gt;After Heroku has finished building, you can open POSTMAN and test our new endpoints and everything should be working well.&lt;/p&gt;

&lt;p&gt;That's all for today, our Authentication endpoints are finished.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: There are a few things we can do to improve our API. For instance, you might have noticed that the tokens of logged out users saved in our Redis database will stay there even after 30 days (after they expire). Since there's no reason to keep storing an expired token, we can set up a CRON job that will run maybe every day at midnight or every end of week or end of month to delete these expired tokens. But this is out of scope for this series now. I might write a post on how to implement such a functionality at the end of this series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the next post, we are going to look at user roles, how to create an admin account, how to create a menu of dishes, ...etc. At the end of the post a customer will be able to place an order.&lt;/p&gt;

&lt;p&gt;I want to thank you who is reading this post right now. If you have a question, comment, suggestion or any other feedback, please feel free to drop it in the comment box below.&lt;/p&gt;




&lt;p&gt;See you in the next post! Happy New Year! 🎉&lt;/p&gt;




&lt;p&gt;The code in this post can be found &lt;a href="https://github.com/the22mastermind/gourmet-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (2)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Sun, 27 Dec 2020 17:02:41 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-2-28po</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-2-28po</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Welcome back!&lt;/p&gt;

&lt;p&gt;Today we are going to start implementing authentication for the backend of our app "Gourmet".&lt;/p&gt;

&lt;p&gt;In this post we will implement the &lt;strong&gt;sign up&lt;/strong&gt; and &lt;strong&gt;verify&lt;/strong&gt; endpoints.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-1-594j"&gt;Backend - Project Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Backend - Authentication

&lt;ol&gt;
&lt;li&gt;
&lt;a href=""&gt;Backend - Authentication - Signup&lt;/a&gt; 📌&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h"&gt;Backend - Authentication - Login and Logout&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - Place order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - View orders list and view a specific order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Backend - Update order&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Authentication&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=""&gt;Frontend - Place order, view orders list, and view order details&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;




&lt;h3&gt;
  
  
  2. Backend - Authentication
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sign up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For users to register on our app, we will require their first name, last name, phone number, address, and password. If the values provided are valid, we will send a OTP (One-Time-Password/Passcode) via SMS to their phone number which they can use to confirm their registration.&lt;/p&gt;

&lt;p&gt;Following the TDD approach, we are first going to write our tests then we will implement validations, middlewares, routes, controllers and finally we will configure Sequelize to be able to save data in the database.&lt;/p&gt;

&lt;p&gt;Before we begin, ensure you have installed and configured &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; properly as it's the database we are going to be using. Check out &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-16-04" rel="noopener noreferrer"&gt;this article&lt;/a&gt; on how to install it on Ubuntu.&lt;/p&gt;

&lt;p&gt;Our signup task is going to be made up of 2 sub-tasks, one for signing up and another for confirming the user's registration. Let's begin with the first one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure you are on your &lt;code&gt;main&lt;/code&gt; branch then run &lt;code&gt;git pull origin main&lt;/code&gt; to make sure your local branch is up to date with the remote branch&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git checkout -b ft-authentication&lt;/code&gt; to create a new branch for today's task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we build our API there are things that we will need often and to avoid repeating ourselves it's good practice to structure our code for re-usability. That being said, create a new directory called &lt;code&gt;utils&lt;/code&gt; inside &lt;code&gt;src&lt;/code&gt;. Create two new files &lt;code&gt;statusCodes.js&lt;/code&gt; and &lt;code&gt;messages.js&lt;/code&gt; inside utils.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/utils/statusCodes.js&lt;/code&gt; and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;These are all the HTTP status codes that our API is going to use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/utils/messages.js&lt;/code&gt; and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This file will contain all the response messages that our API will be returning to the client apps on top of status codes and other data.&lt;/p&gt;

&lt;p&gt;Now let's write our tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file called &lt;code&gt;authentication.test.js&lt;/code&gt; in tests directory and paste the following inside:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this file, we import our express app along with our assertion libraries (chai and chai-http) and our status codes and messages we defined above. We then define a base URL for our authentication routes and we initialize chai to be able to test http apps. Learn more about &lt;a href="https://www.chaijs.com/" rel="noopener noreferrer"&gt;chai here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We then define a &lt;code&gt;SIGN UP&lt;/code&gt; suite to hold our 5 test cases. In the first test case, we are testing for when a user submits an empty request (tries to signup without providing any data), what response he/she should get. Notice the use of one of our status code and messages we defined earlier.&lt;/p&gt;

&lt;p&gt;In the second test case, we are testing for when a user submits an invalid phone number. Notice the missing &lt;code&gt;+&lt;/code&gt; sign on the phone number. The phone number must be in a valid international format since we will use it to send the OTP.&lt;/p&gt;

&lt;p&gt;In the third test case, we are testing for when a user submits any other value apart from the required ones (firstName, lastName, phoneNumber, address, and password). Notice the email property.&lt;/p&gt;

&lt;p&gt;In the fourth test case, we are testing for when a user submits valid values conforming to validation rules that we will define next. In this case, we expect a successful response that contains a status code of &lt;code&gt;201&lt;/code&gt;, a &lt;code&gt;account created&lt;/code&gt; message, a JWT token that the user can use to authenticate for subsequent requests, and a data object containing details of the user. Notice how we expect the user's account status to be false since he/she has not yet verified it. Finally, we retrieve the token in a variable called &lt;code&gt;userToken&lt;/code&gt; that we will use in other test cases when verifying the user's account.&lt;/p&gt;

&lt;p&gt;In the fifth test case, we are testing for when a user tries to signup more than once using the same phone number.&lt;/p&gt;

&lt;p&gt;At this point if you run the tests they will fail apart from &lt;code&gt;Server initialization test&lt;/code&gt; which is exactly what we want.&lt;/p&gt;

&lt;p&gt;Next up is to write code to make our tests pass.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create the following directories &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;controllers&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt;, &lt;code&gt;helpers&lt;/code&gt;, &lt;code&gt;middlewares&lt;/code&gt;, &lt;code&gt;routes&lt;/code&gt;, &lt;code&gt;services&lt;/code&gt;, and &lt;code&gt;validations&lt;/code&gt; inside &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new file called &lt;code&gt;authentication.js&lt;/code&gt; inside validations directory and paste the following code inside:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We will use this file for authentication validation. In the code above, we start by importing a library called &lt;code&gt;Joi&lt;/code&gt; and our response messages we defined in utils. Joi is a powerful data validator for Javascript and I personally like it because it is robust and easy to use. Check out its docs &lt;a href="https://joi.dev/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We created a function &lt;code&gt;createErrorMessages&lt;/code&gt; to help us in - you guessed it - create validation error messages. The function takes &lt;code&gt;error type&lt;/code&gt; and &lt;code&gt;empty, min, max, and pattern&lt;/code&gt; custom messages as parameters and depending on the type of the error we assign a custom message. This function returns an object of error types and their messages.&lt;/p&gt;

&lt;p&gt;We use the second function &lt;code&gt;signup&lt;/code&gt; to define a schema of values that we want users to submit when signing up. Notice the use of Regular Expressions to enforce validation rules. If you're familiar with RegEx, it's pretty straight forward as our use-case is not too complex.&lt;/p&gt;

&lt;p&gt;Finally we call Joi's built-in method &lt;code&gt;validate&lt;/code&gt; on our schema and pass in a data object i.e. req.body and some options to return all errors at once and to prevent other values not defined in our schema. Check out &lt;a href="https://joi.dev/api/" rel="noopener noreferrer"&gt;Joi API&lt;/a&gt; for more details and advanced use-cases.&lt;/p&gt;

&lt;p&gt;In case of errors, our signup validation function will return an &lt;code&gt;errors&lt;/code&gt; object containing a &lt;code&gt;details&lt;/code&gt; property. This details property is an array containing all the error messages. We need a way to extract and use the contents of this details property.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;misc.js&lt;/code&gt; file inside &lt;code&gt;helpers&lt;/code&gt; directory and paste the following code:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this file we define 3 functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We will use &lt;code&gt;successResponse&lt;/code&gt; and &lt;code&gt;errorResponse&lt;/code&gt; to return success and error responses respectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;returnErrorMessages&lt;/code&gt; checks to see if the parameter &lt;code&gt;errors&lt;/code&gt; is present then destructure its details property. We then format each message in our details array to make it more readable and then we use &lt;code&gt;errorResponse&lt;/code&gt; defined above to return the result of these formatted messages.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If errors is null it means our validations are passing and we continue with the execution of the request. Think of &lt;code&gt;returnErrorMessages&lt;/code&gt; as a middleware.&lt;/p&gt;

&lt;p&gt;Let's now use this &lt;code&gt;returnErrorMessages&lt;/code&gt; function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file &lt;code&gt;authentication.js&lt;/code&gt; in middlewares directory and paste the following code:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Notice the use of &lt;code&gt;returnErrorMessages&lt;/code&gt; by giving it the error object returned by our signup validation function as a parameter.&lt;/p&gt;

&lt;p&gt;Before we implement our controller, let's update &lt;code&gt;src/helpers/misc.js&lt;/code&gt; with the following:&lt;/p&gt;

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

&lt;p&gt;Notice the additional functions: &lt;code&gt;generateToken&lt;/code&gt;, &lt;code&gt;generateOTP&lt;/code&gt;, and &lt;code&gt;generateHashedPassword&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will use &lt;code&gt;generateToken&lt;/code&gt; to generate a JWT token based on the data passed in. Update your &lt;code&gt;.env&lt;/code&gt; file and include the &lt;code&gt;JWT_SECRET_KEY&lt;/code&gt; like &lt;code&gt;JWT_SECRET_KEY=somesecretkey&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will use &lt;code&gt;generateOTP&lt;/code&gt; to generate a random six digit code that we will send to a user.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;generateHashedPassword&lt;/code&gt; will be used to take a plain-text password, encrypt it and return a hash string which we will store in our database. For security reasons, &lt;strong&gt;You should never store plain-text passwords in your database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Okay, let's implement our controller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;authentication.js&lt;/code&gt; file in &lt;code&gt;controllers&lt;/code&gt; directory and paste the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Our controller is where a request that has passed all validations and middlewares will end its journey. This where we will implement saving data in the database and sending OTP to users before returning a response to the user.&lt;/p&gt;

&lt;p&gt;Let's implement our routes to see how it looks so far.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create two files &lt;code&gt;authRoutes.js&lt;/code&gt; and &lt;code&gt;index.js&lt;/code&gt; in routes directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Paste the following inside &lt;code&gt;src/routes/authRoutes.js&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If you remember, in our tests we defined our base URL as &lt;code&gt;/api/auth/&lt;/code&gt;. This means we will be able to define &lt;code&gt;/api/auth/signup&lt;/code&gt;, &lt;code&gt;/api/auth/login&lt;/code&gt;, and &lt;code&gt;/api/auth/logout&lt;/code&gt; routes respectively.&lt;/p&gt;

&lt;p&gt;Let's implement the parent &lt;code&gt;/api/auth/&lt;/code&gt; route handler.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paste the following inside &lt;code&gt;src/routes/index.js&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Our endpoint is almost complete. We just need to let our express app know about it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/server.js&lt;/code&gt; to look look like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Run your tests again. This time around, some of them are passing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Great Job if you managed to reach here! 🎉&lt;/p&gt;

&lt;p&gt;Let's now implement sending OTP. When we finish, we will setup Sequelize in order to persist data in the database.&lt;/p&gt;

&lt;p&gt;Starting with OTP implementation, we are going to use &lt;a href="https://www.twilio.com/" rel="noopener noreferrer"&gt;Twilio&lt;/a&gt;. Click &lt;a href="https://www.twilio.com/try-twilio" rel="noopener noreferrer"&gt;here&lt;/a&gt; to create a Twilio trial account. After creating your account you should be given some credit you can use to buy numbers and send SMS in trial mode.&lt;/p&gt;

&lt;p&gt;Trial accounts have some limitations, namely you cannot send SMS to unverified numbers. So in order to test this functionality, there are 2 options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1&lt;/strong&gt;&lt;br&gt;
You can upgrade your account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2&lt;/strong&gt;&lt;br&gt;
You can verify numbers you intend to use. Just remember to upgrade your account before going into production to allow everyone to signup.&lt;/p&gt;

&lt;p&gt;We are going to use option 2 for now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Login to your Twilio account. Click on the &lt;code&gt;#&lt;/code&gt; sign that says &lt;code&gt;Phone numbers&lt;/code&gt; on the left panel. On the phone numbers page, click &lt;code&gt;Buy number&lt;/code&gt; button and proceed to search for a number you want. Make sure to tick the SMS checkbox.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;code&gt;Verified Caller IDs&lt;/code&gt; then click on the red plus button to add and verify a number. Make sure to provide a valid phone number that you have access to because Twilio will send a OTP to verify it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once done, head back to VS Code and add the following keys in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

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

&lt;p&gt;Let's now install the Twilio library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open your terminal in your project's root dir and run &lt;code&gt;yarn add twilio&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;twilioConfig.js&lt;/code&gt; file in config directory and paste the following:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this file we initialize a twilio client instance that we can use throughout our app to send SMS.&lt;/p&gt;

&lt;p&gt;Let's now use this client in our code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/heplers/misc.js&lt;/code&gt; to look like the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The &lt;code&gt;sendOTP&lt;/code&gt; function will take a phone number and a message and it will take care of sending our SMS. Let's now use this function in our controller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now run your tests again and you should get a OTP delivered to the number you specified in &lt;code&gt;TWILIO_CUSTOMER_NUMBER&lt;/code&gt; env variable.&lt;/p&gt;

&lt;p&gt;Great! Let's now implement &lt;a href="https://sequelize.org/" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; and save data in our database.&lt;/p&gt;

&lt;p&gt;Since we already installed all the required sequelize library and plugins, let's start using them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your terminal, navigate to &lt;code&gt;src/database&lt;/code&gt; and run &lt;code&gt;npx sequelize-cli init&lt;/code&gt;. This command will create the following directories and files: &lt;code&gt;config/config.json&lt;/code&gt;, &lt;code&gt;models&lt;/code&gt;, &lt;code&gt;migrations&lt;/code&gt;, and &lt;code&gt;seeders&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The models directory will contain our models. Think of models as tables in a database.&lt;/p&gt;

&lt;p&gt;The migrations directory will contain migrations which are modifications made to our models. We use migrations to change the structure our 'tables'. We can do things like add/remove/rename columns, add/change constraints on columns, etc.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that each time we modify the structure of our models we need to run migrations for those changes to take effect. More on this later.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;seeders&lt;/code&gt; directory will contain data that we want to inject in the database. Use-case: Imagine you want to test the &lt;code&gt;login&lt;/code&gt; functionality. since we have already implemented the signup tests and we know it works well, we can use the seeders to insert in the database valid records of users thus skipping the signup and verify tests which will make our tests run faster. We will use seeders later in this series.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;config.json&lt;/code&gt; file will contain credentials to connect to our database. We will need to modify this file and make it dynamic to avoid exposing our database credentials. Let's do it right away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rename &lt;code&gt;src/database/config/config.json&lt;/code&gt; to &lt;code&gt;src/database/config/config.js&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace the contents inside with:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Update your &lt;code&gt;.env&lt;/code&gt; file and add the keys for development and test like below:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Notice the different database names for development and test.&lt;/p&gt;

&lt;p&gt;Note that for now we &lt;strong&gt;don't&lt;/strong&gt; need to provide credentials for production in our &lt;code&gt;.env&lt;/code&gt; file. The production credentials will be provided to us by heroku when we "provision" (setup) a production database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;src/database/models/index.js&lt;/code&gt; with the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This file will allow us to import our models dynamically by doing something like: &lt;code&gt;import models from '../database/models'&lt;/code&gt; then destructure models to retrieve each model in models directory. This file also creates and exports a sequelize instance that we will be using to interact with the database.&lt;/p&gt;

&lt;p&gt;Cool! Let's now use Sequelize to create our first model - User.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your terminal run &lt;code&gt;npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,phoneNumber:string,address:string&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This command will create 2 new files: &lt;code&gt;user.js&lt;/code&gt; (our user model) and &lt;code&gt;**-create-user.js&lt;/code&gt; (our first migration) inside models and migrations directories respectively.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;package.json&lt;/code&gt; to include commands to create and drop the database as well as run the migrations like:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Notice we didn't include the &lt;code&gt;pretest&lt;/code&gt; command on the &lt;code&gt;test&lt;/code&gt; command since our CI service does this automatically for each build.&lt;/p&gt;

&lt;p&gt;If we were to run our migrations right now, our database would be created with just the 4 columns defined when creating our model above.&lt;/p&gt;

&lt;p&gt;Let's update our model and add more columns and create a new migration to apply those changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/database/models/user.js&lt;/code&gt; like below:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;In your terminal run &lt;code&gt;npx sequelize-cli migration:generate --name add-password-otp-and-status-to-user&lt;/code&gt; to create a new migration that will apply the new columns we added to our model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Tip: As migrations can become many as our app scales, it's good practice to name each migration with what it does. By looking at the name of the new migration, we would know that it add password, otp, and status columns to user model.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace the contents of &lt;code&gt;src/database/migrations/**-add-password-otp-and-status-to-user.js&lt;/code&gt; with the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Check out &lt;a href="https://sequelize.org/master/manual/migrations.html" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to learn more about creating models and migrations.&lt;/p&gt;

&lt;p&gt;If we were to run our 2 migrations now, all the 7 columns would be added to our user table.&lt;/p&gt;

&lt;p&gt;One of the things I like about Sequelize is its nice API that allows to interact with the database without writting SQL queries like "INSERT INTO tableName VALUES(....". Oh! This API allows also to write those queries in case you wish to use them. Nice, right!&lt;/p&gt;

&lt;p&gt;We are almost done!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;services.js&lt;/code&gt; file inside services directory and paste the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We will be using this file to create functions that will use Sequelize API to CRUD the database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;saveData&lt;/code&gt; function receives a model name and obj as parameters then calls the Sequelize built-in method &lt;code&gt;create&lt;/code&gt; on the model and returns the data saved in the database.&lt;/p&gt;

&lt;p&gt;Similarly we use &lt;code&gt;findByCondition&lt;/code&gt; function to find if a record exists in a table given a conditon. Check out &lt;a href="https://sequelize.org/master/manual/model-querying-basics.html" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to learn more about these built-in model methods.&lt;/p&gt;

&lt;p&gt;As you might have guessed, we will use &lt;code&gt;findByCondition&lt;/code&gt; to check if a user exists in the database and &lt;code&gt;saveData&lt;/code&gt; to save the user.&lt;/p&gt;

&lt;p&gt;Okay, let's update &lt;code&gt;src/middlewares/authentication.js&lt;/code&gt; to look like the following:&lt;/p&gt;

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

&lt;p&gt;We need to run this function after the validations and before the controller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;src/routes/authRoutes.js&lt;/code&gt; to look like:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Lastly, let's update our controller to use the &lt;code&gt;saveData&lt;/code&gt; function we defined in our services. Update &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; to look like the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the code above we added the &lt;code&gt;saveData&lt;/code&gt; and lodash's &lt;code&gt;omit&lt;/code&gt; and &lt;code&gt;pick&lt;/code&gt; methods to choose which properties should be in the userData object returned in the response and token respectively.&lt;/p&gt;

&lt;p&gt;That's it! Our signup endpoint is done!&lt;/p&gt;

&lt;p&gt;Now if you run your tests, they should all pass! Nice, right!&lt;/p&gt;

&lt;p&gt;In case you run into a timeout error, make sure to update your script's test command in &lt;code&gt;package.json&lt;/code&gt; by adding a timeout flag like below:&lt;/p&gt;

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

&lt;p&gt;This allows to extend the default Mocha's timeout of 2 seconds for each test case to 8 seconds which will give enough time to our asynchronous functions to finish executing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Verify&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After users have registered and we have sent the OTP, we need a way to verify their phone number thus confirming their account registration. &lt;/p&gt;

&lt;p&gt;We are going to implement &lt;strong&gt;verify endpoints&lt;/strong&gt;, the first one will be to check if the OTP submitted by the user is correct. The second will be to re-send the OTP to the user in case there has been an issue and the user didn't receive the first OTP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;tests/authentication.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In the code above, we have added test cases for the &lt;code&gt;verify&lt;/code&gt; and &lt;code&gt;verify/retry&lt;/code&gt; endpoints.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;SIGNUP&lt;/code&gt; test suite, update &lt;code&gt;Valid signup should return 201&lt;/code&gt; test case like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/utils/messages.js&lt;/code&gt; and add the following messages:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/validations/authentication.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/middlewares/authentication.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;validateVerifyOTP&lt;/code&gt; middleware will help us to use &lt;code&gt;verifyOTP&lt;/code&gt; function to validate the &lt;code&gt;otp&lt;/code&gt; submitted by the user.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;checkUserToken&lt;/code&gt; middleware will help us to check if a request contains the Authorization header then will try to decode the token to check if the who made the request exists in our database then returns the user's data or an error. This is how we will be able to link users with their requests.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;checkOTP&lt;/code&gt; middleware will help us to check if the otp submitted by the user is the same as the one we sent to them via SMS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/services/services.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/controllers/authentication.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;src/routes/authRoutes.js&lt;/code&gt; and add the following:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now all our tests should be passing. Let's now update our travis config file and package.json file before we commit our changes to Github.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;.travis.yml&lt;/code&gt; file to look like this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We added the &lt;code&gt;services&lt;/code&gt; option and &lt;code&gt;before_script&lt;/code&gt; command which will tell Travis to create a postgres database called &lt;code&gt;gourmet_test&lt;/code&gt; before running our tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;package.json&lt;/code&gt; to include a &lt;code&gt;heroku-postbuild&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;As the name suggests, this command will run after each build. You can use it to run scripts that you want to execute before your app is deployed. Here we are using it to run our migrations automatically.&lt;/p&gt;

&lt;p&gt;The last step is to make sure our CI service and production environments are up to date.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login on &lt;a href="https://travis-ci.com/" rel="noopener noreferrer"&gt;Travis&lt;/a&gt; then open our &lt;code&gt;gourmet-api&lt;/code&gt; repo then click on settings to add environments variables. Make sure to add each env variable with its value.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Head back to VS Code and commit our changes to github. Open a PR on github and wait for Travis to finish building. Both the branch and PR should show a successful build.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we merge this PR, let's create a production database on heroku.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On your app page on heroku, click on &lt;code&gt;Resources&lt;/code&gt; tab then in the &lt;code&gt;Add-ons&lt;/code&gt; search field type &lt;code&gt;postgres&lt;/code&gt;. Select &lt;code&gt;Heroku Postgres&lt;/code&gt; and in the confirmation modal click &lt;code&gt;Submit order form&lt;/code&gt;. You should see a confirmation that the add-on &lt;code&gt;heroku-postgresql&lt;/code&gt; has been added. Check out the &lt;a href="https://devcenter.heroku.com/articles/heroku-postgresql" rel="noopener noreferrer"&gt;docs&lt;/a&gt; for more info.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;code&gt;Heroku Postgres&lt;/code&gt; to open it in a new tab then click on &lt;code&gt;Settings&lt;/code&gt; tab then click the &lt;code&gt;View credentials&lt;/code&gt; button.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should see the credentials of our database. When you provision a database on heroku like this, it adds the &lt;code&gt;DATABASE_URL&lt;/code&gt; env variable automatically on your app.&lt;/p&gt;

&lt;p&gt;Let's now add the database credentials as env variables. Alternatively, you could use the &lt;code&gt;DATABASE_URL&lt;/code&gt; variable in the &lt;code&gt;database/config/config.js&lt;/code&gt; and &lt;code&gt;database/models/index.js&lt;/code&gt; files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On your main app's settings tab, click on &lt;code&gt;Reveal config vars&lt;/code&gt; button and add each credential key and its corresponding value from the database we've just created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't forget our Twilio credentials and JWT_SECRET_KEY&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now it's time to merge our PR which will trigger a production build on heroku.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Head over to github and merge the PR we created earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Travis should build our merge commit successfully then Heroku should build successfully as well then run our migrations.&lt;/p&gt;

&lt;p&gt;Now you could copy the URL of your app from heroku and test the endpoints we implemented with POSTMAN or Insomnia and everything should go smoothly. Check out the links to their docs below.&lt;/p&gt;

&lt;p&gt;Today's task was huge because we covered a lot of things. But we have laid the foundation for Sequelize, validations, and middlewares. The next endpoints are going to be fairly straightforward.&lt;/p&gt;

&lt;p&gt;In the next post, we will implement the &lt;code&gt;login&lt;/code&gt; and &lt;code&gt;logout&lt;/code&gt; endpoints.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip: To test your API as you build it, you should use a tool like &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; or &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;They are both great at designing and testing APIs and you can even do things like creating and hosting your API documentation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check out the &lt;a href="https://learning.postman.com/docs/getting-started/introduction/" rel="noopener noreferrer"&gt;Postman docs&lt;/a&gt; and &lt;a href="https://support.insomnia.rest/category/9-getting-started" rel="noopener noreferrer"&gt;Insomnia docs&lt;/a&gt; to learn more.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The endpoints we implemented in this post are a bit naive. For example, we are not checking if a user's account is verified before verifying it. We should also limit requests to the endpoints that uses external resources since the billing of these resources can become a lot. Check out this &lt;a href="https://www.npmjs.com/package/express-rate-limit" rel="noopener noreferrer"&gt;library&lt;/a&gt; to learn how to limit the number of requests. About the other issue of checking if a user's account is verified before verifying it, we can achieve this by using a simple middleware function.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading and or following along!&lt;/p&gt;

&lt;p&gt;See you in the next one!&lt;/p&gt;




&lt;p&gt;You can find the code in this post &lt;a href="https://github.com/the22mastermind/gourmet-api" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Online Food Ordering App (1)</title>
      <dc:creator>Bertrand Masabo</dc:creator>
      <pubDate>Wed, 16 Dec 2020 18:56:20 +0000</pubDate>
      <link>https://dev.to/the22mastermind/online-food-ordering-app-1-594j</link>
      <guid>https://dev.to/the22mastermind/online-food-ordering-app-1-594j</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;abillion&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today we are going to build an online food ordering app called "Gourmet". The app will be made of a REST API as the back-end and 2 react apps as the front-end, namely a react Admin Panel and a customer facing react-native mobile app.&lt;/p&gt;

&lt;p&gt;Throughout the project, we are going to use the TDD approach, ES6, and CI/CD among other things.&lt;/p&gt;

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

&lt;p&gt;The following are the requirements for our project, but you can expand it and add more features as you wish.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication: a customer should be able to signup, login and logout&lt;/li&gt;
&lt;li&gt;View menu and place order: a customer should be able to view the restaurant's menu, select the items she wants then place an order.&lt;/li&gt;
&lt;li&gt;View orders and order details: a customer should be able to view the orders she has placed and their details.&lt;/li&gt;
&lt;li&gt;Update order: the admin should be able to view all the orders placed, their details and should be able to update a specific order.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Project steps
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;a href=""&gt;Backend - Project Setup&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  2. &lt;a href="https://dev.to/the22mastermind/online-food-ordering-app-2-28po"&gt;Backend - Authentication&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  3. &lt;a href=""&gt;Backend - Place order&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  4. &lt;a href=""&gt;Backend - View orders list and view a specific order&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  5. &lt;a href=""&gt;Backend - Update order&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  6. &lt;a href=""&gt;Frontend - Authentication&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  7. &lt;a href=""&gt;Frontend - Place order, view orders list, and view order details&lt;/a&gt;
&lt;/h4&gt;

&lt;h3&gt;
  
  
  1. Backend - Project Setup
&lt;/h3&gt;

&lt;p&gt;To kick things off, create a github repo, copy your repo's URL, open your terminal, navigate to a directory where you wish your project to reside then enter the following command &lt;code&gt;git clone https://github.com/&amp;lt;YOUR_GITHUB_USERNAME&amp;gt;/&amp;lt;YOUR_REPO_NAME&amp;gt;.git&lt;/code&gt;.&lt;br&gt;
Alternatively, you could use GitHub CLI or SSH if you want.&lt;/p&gt;

&lt;p&gt;After the above steps, enter &lt;code&gt;ls&lt;/code&gt; command and you should see the name of your repo. Enter &lt;code&gt;cd YOUR_REPO_NAME&lt;/code&gt; to go into your project directory and we are good to go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure you have &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js v10+&lt;/a&gt; installed before proceeding by running &lt;code&gt;node -v&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;git checkout -b chore-project-setup-init&lt;/code&gt; to create a new branch for our first task of project setup.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;yarn init -y&lt;/code&gt; to initialize a new project. Alternatively, you could use &lt;code&gt;npm init&lt;/code&gt; but I prefer yarn for it's easy to read CLI output, faster package installation speed, and offline mode among other things. Google &lt;strong&gt;yarn vs npm&lt;/strong&gt; to find out the pros and cons one has over the other.&lt;/li&gt;
&lt;li&gt;Open your project in VSCode by running &lt;code&gt;code .&lt;/code&gt; in the root directory of your project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;yarn add express body-parser cors dotenv joi jsonwebtoken lodash make-runnable moment morgan pg pg-hstore sequelize sequelize-cli sequelize-test-helpers bcrypt&lt;/code&gt; to install the packages we are going to be using.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;yarn add @babel/core @babel/node @babel/plugin-syntax-class-properties @babel/plugin-transform-runtime @babel/preset-env babel-eslint babel-plugin-istanbul&lt;/code&gt; to install babel and its plugins which will help to convert our ES6 Javascript code into backwards compatible versions for older browsers and environments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dev-dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;yarn add --dev eslint @babel/register chai chai-http coveralls cross-env mocha mocha-lcov-reporter nodemon nyc&lt;/code&gt; to install dev-dependencies which are packages used mainly in development and testing environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configure ESLint&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;yarn run eslint --init&lt;/code&gt; to start ESLint configuration.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flg9ur5618ee0szbaaiug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flg9ur5618ee0szbaaiug.png" alt="carbon"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmgcg4xllxwauptakiauz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmgcg4xllxwauptakiauz.png" alt="carbon (1)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42041f3mry7978mj5wj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42041f3mry7978mj5wj5.png" alt="carbon (2)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6aobld29re5jqybm0z5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6aobld29re5jqybm0z5c.png" alt="carbon (3)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo25gbc7est8lv5gkxpuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo25gbc7est8lv5gkxpuj.png" alt="carbon (4)"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Select Node only&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F79npy9btr8l1wi1x0hzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F79npy9btr8l1wi1x0hzd.png" alt="carbon (5)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr0fv7l67r6b3mhtblli4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr0fv7l67r6b3mhtblli4.png" alt="carbon (6)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxwuy04b2mhyke311k8mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxwuy04b2mhyke311k8mm.png" alt="carbon (7)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are asked to install additional ESLint dependencies, select yes and Enter. This last step should look like the image below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9qq70sjd31n4gir5z326.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9qq70sjd31n4gir5z326.png" alt="carbon (8)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the root directory of your project, you should see a new config file called .eslintrc.json. Learn more about ESLint &lt;a href="https://eslint.org/docs/user-guide/getting-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In the root directory of our project, there's a new file called package-lock.json will was created by npm after installing the additional ESLint packages. We are now using 2 package managers (yarn and npm). This is not ideal.&lt;/p&gt;

&lt;p&gt;Let's stick to one (i.e. yarn).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete &lt;strong&gt;package-lock.json&lt;/strong&gt; file and &lt;strong&gt;node_modules&lt;/strong&gt; directory&lt;/li&gt;
&lt;li&gt;In the terminal, make sure you are in the root directory of your project and run &lt;code&gt;yarn install&lt;/code&gt; to install all our dependencies afresh&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configure package.json&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open package.json file in VSCode and the following scripts key with start and dev command to start our server in production and development environments respectively&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Let's create that server.js file. In your terminal run &lt;code&gt;mkdir src &amp;amp;&amp;amp; touch src/server.js&lt;/code&gt;. You should see an empty server.js file inside src dir.&lt;/li&gt;
&lt;li&gt;Make sure to update your main entry file to &lt;code&gt;server.js&lt;/code&gt; as well.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9n0xesy54h36sokw1nb0.png" alt="carbon (10)"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configure server.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's test if our server can start up. Add the following statement &lt;code&gt;console.log('Server is up and running');&lt;/code&gt; in server.js and save. At this point you should see a ESLint warning because of that console.log() statement.&lt;/p&gt;

&lt;p&gt;In the terminal, navigate to the project's root dir and run &lt;code&gt;yarn dev&lt;/code&gt;. You should see 'Server is up and running' being logged in the terminal. Change 'Server is up and running' in server.js to 'Server is up!' and save, the server should restart automatically to reflect your new changes. This is made possible by the nodemon package we specified in the dev script and it's going to allow us to focus on building our api without worrying about stopping and starting our server each time we make changes.&lt;/p&gt;

&lt;p&gt;Create a .babelrc configuration file in your project's root dir and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feqp6mj1tkr58b5jjx0xg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feqp6mj1tkr58b5jjx0xg.png" alt="carbon (11)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't forget to replace 14 with your version of Node.&lt;/p&gt;

&lt;p&gt;At this point our server is not doing much. Let's change that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your terminal run &lt;code&gt;Ctrl+C&lt;/code&gt; to stop the server.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a .env file in your project's root dir and inside put PORT=4000 and save. This will be the port number our server will use in development and local testing environments. When we go into CI or production, the port will be provided dynamically by the platform we will be using, hence the &lt;code&gt;process.env.PORT&lt;/code&gt; instead of hardcoding the port value. This .env file will also allow us to keep track of all the sensitive keys, secrets, and passwords that should not be exposed to the public. Remember to keep this file outside of version control systems. Speaking of which, let's do it right away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a .gitignore file in your project's root dir and add the following inside:
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fidmsowtpsfeylmwzxa3o.png" alt="carbon (12)"&gt;
&lt;/li&gt;
&lt;li&gt;Notice &lt;code&gt;node_modules/&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt;. Basically, everything we put in this file will not be committed to github. Check out &lt;a href="https://www.freecodecamp.org/news/gitignore-what-is-it-and-how-to-add-to-repo/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; to learn more.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Replace the console statement inside server.js with the following code and save:&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwa9fs1ktc4hqf57cl5lq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwa9fs1ktc4hqf57cl5lq.png" alt="carbon (13)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Run &lt;code&gt;yarn dev&lt;/code&gt; and you should see the server running with message &lt;code&gt;Live at 4000&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Open your browser and navigate to &lt;a href="http://localhost:4000" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="http://localhost:4000" rel="noopener noreferrer"&gt;http://localhost:4000&lt;/a&gt; and you should see the following response: &lt;code&gt;{"error":"Route not found"}&lt;/code&gt; which is exactly what we expect since we haven't yet implemented our API routes.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you reached this step, &lt;strong&gt;CONGRATULATIONS!&lt;/strong&gt;🎉🎉🎉&lt;/p&gt;

&lt;p&gt;Just 1 or 2 things remaining and then we deploy our API 🔥&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So far we have managed to implement the substructure of our API. Next up we are going to write tests, setup Continuous Integration and Continuous Delivery (CI/CD).&lt;/p&gt;

&lt;p&gt;I recommend deploying your app early on because it helps to detect and debug issues when your codebase is still small. Another advantage is that you can ship features that your users can start using without waiting for the entire app to be done.&lt;/p&gt;

&lt;p&gt;Okay, let's do it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the project's root dir, create a new dir &lt;code&gt;tests&lt;/code&gt; and inside tests create a file called &lt;code&gt;server.js&lt;/code&gt; and paste the following code inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7ozkd6pmpxsxj0gtqd8n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7ozkd6pmpxsxj0gtqd8n.png" alt="carbon (15)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update your scripts in package.json and add a &lt;code&gt;dev-test&lt;/code&gt; command like:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsn8rxorcm6wxixydnayc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsn8rxorcm6wxixydnayc.png" alt="carbon (16)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the command we will use in development to run our tests which will produce a nice table in terminal showing test coverage. We need another command for our CI service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add the &lt;code&gt;test&lt;/code&gt; command like below:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjduas05hibi2mq70aji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzjduas05hibi2mq70aji.png" alt="carbon (17)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When our hosted CI service will finish running the above &lt;code&gt;test&lt;/code&gt; command, it will create a coverage directory which contains the coverage results of our tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check out &lt;a href="https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to add Travis-ci to your github repo. There's a lot more you can do with Travis, make sure to check out their &lt;a href="https://docs.travis-ci.com/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;code&gt;.travis.yml&lt;/code&gt; configuration file in your project root directory and paste the following inside:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxe3zqp692al3ky2bghtt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxe3zqp692al3ky2bghtt.png" alt="carbon (19)"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Time to commit our changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;git add .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git commit -m "chore(project-setup-init):pre-deployment"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git push origin chore-project-setup-init&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Back on github, raise a PR and you should see your branch build successfully.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We want our production build to be based off the master/main branch of our github repo. Basically, we will be creating new branches, build features, test locally, commit to github then test with Travis-CI, then merge to main branch which will trigger a new build of our production build. Yes, I said build of a build 😆.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signup on &lt;a href="https://signup.heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt; and login&lt;/li&gt;
&lt;li&gt;Create a new app, then switch to the &lt;strong&gt;deploy&lt;/strong&gt; tab then scroll down to deployment method and select GitHub and you should see a Connect to GitHub option below&lt;/li&gt;
&lt;li&gt;Select your github username and your github repo. Type the name of your repo and hit search if it doesn't show up then click &lt;code&gt;connect&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You should see that your app is now connected to github and a &lt;strong&gt;Automatic deploys&lt;/strong&gt; option below&lt;/li&gt;
&lt;li&gt;&lt;p&gt;on &lt;strong&gt;Automatic deploys&lt;/strong&gt; select main/master branch, tick &lt;code&gt;Wait for CI to pass before deploy&lt;/code&gt;, then hit &lt;strong&gt;Enable Automatic deploys&lt;/strong&gt; button and that's it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Head back to your PR on github and merge it. Travis-CI should build our merge commit successfully which will then trigger our production build on heroku.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On heroku, the &lt;strong&gt;Activity&lt;/strong&gt; tab should show a &lt;strong&gt;Build succeeded&lt;/strong&gt; status.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hit &lt;strong&gt;Open app&lt;/strong&gt; button and we should see our &lt;code&gt;{"error":"Route not found"}&lt;/code&gt; error message. This is good. it's a good error 😄.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our API is now live 🔥.&lt;/p&gt;

&lt;p&gt;In the next post we will focus on implementing authentication namely signup, login, and logout functionalities. We will cover the concepts of JWT token, Postgres, and Sequelize ORM among other things.&lt;/p&gt;

&lt;p&gt;Thank you for reading, see you in the next one!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gourmetfood-api.herokuapp.com/" rel="noopener noreferrer"&gt;Demo Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/the22mastermind/gourmet-api/tree/chore-project-setup-init" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
