<?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: Kenneth Angelo Reyes</title>
    <description>The latest articles on DEV Community by Kenneth Angelo Reyes (@projectkenneth).</description>
    <link>https://dev.to/projectkenneth</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%2F694910%2F75525e6a-aef3-4749-b555-9fce5e52e727.jpeg</url>
      <title>DEV Community: Kenneth Angelo Reyes</title>
      <link>https://dev.to/projectkenneth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/projectkenneth"/>
    <language>en</language>
    <item>
      <title>Dynamic Component Rendering in React</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Tue, 26 Oct 2021 18:38:26 +0000</pubDate>
      <link>https://dev.to/projectkenneth/dynamic-component-rendering-in-react-1o97</link>
      <guid>https://dev.to/projectkenneth/dynamic-component-rendering-in-react-1o97</guid>
      <description>&lt;p&gt;When defining application components, a good strategy is to split by functionality.&lt;/p&gt;

&lt;p&gt;In a blogging application, we'll have a component to represent the WYSIWYG editor then, another to hold the publish settings. In this particular example, the publish settings component is pretty static. Meaning, it will always have the same fields and behavior.&lt;/p&gt;

&lt;p&gt;But, what if the publish settings contents vary dynamically? A good example of this can be found in Photoshop. In this case, depending on the tool selected, the Property Panel will be rendered differently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_SiIMuZr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulc4kn77b1gkqt57ziwb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_SiIMuZr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulc4kn77b1gkqt57ziwb.gif" alt="Photoshop Tool Property Panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where dynamic component rendering comes in. When a tool is selected, Photoshop will intelligently determine what will be rendered on the property pane.&lt;/p&gt;

&lt;p&gt;In this post, let's explore how to implement dynamic component rendering in React.&lt;/p&gt;

&lt;p&gt;Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Design
&lt;/h2&gt;

&lt;p&gt;In this section, we'll talk about what makes up a dynamic component rendering implementation.&lt;/p&gt;

&lt;p&gt;There are 3 items we need to prepare:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; - In its most basic form, the configuration is simply a mapping between a condition and a component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Components&lt;/strong&gt; - Of course, we'd need to have the components that will actually be dynamically rendered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Render Function&lt;/strong&gt; - This is the function that will actually perform the decision of which component to render.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, we'll look at dynamic component rendering in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Implementation
&lt;/h2&gt;

&lt;p&gt;For our example, we'll look at a Property Editor component whose contents can be dynamically changed based on user selection.&lt;/p&gt;

&lt;p&gt;We'll configure each of the 3 items mentioned in the previous section. Let's start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;For the configuration, we'll implement a basic mapping between a key and a functional component to represent that key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Config = {
  assign: AssignPropertyEditor,
  log: LogPropertyEditor
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on this configuration, our dynamic component renderer will have 2 different components to choose from.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Components
&lt;/h3&gt;

&lt;p&gt;For the dynamic components, we implement them as if they're normal components.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AssignPropertyEditor&lt;/code&gt; component looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const AssignPropertyEditor = ({ codeData, updateData }) =&amp;gt; {
    const type = codeData.type;
    const localData = codeData.data;

    if (type === "assign") {
        const onVariableChange = (event) =&amp;gt; {
            localData.variable = event.target.value;

            updateData(localData);
        };

        const onValueChange = (event) =&amp;gt; {
            localData.value = event.target.value;

            updateData(localData);
        };

        return (
            &amp;lt;div&amp;gt;
                &amp;lt;strong&amp;gt;Assign:&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
                &amp;lt;input name="assign_var" type="text" defaultValue={localData.variable} placeholder="Variable" onChange={onVariableChange} /&amp;gt;
                &amp;amp;nbsp;=&amp;amp;nbsp;
                &amp;lt;input name="assign_val" type="text" defaultValue={localData.value} placeholder="Value" onChange={onValueChange} /&amp;gt;
            &amp;lt;/div&amp;gt;
        );
    } 

    return null;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the &lt;code&gt;LogPropertyEditor&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const LogPropertyEditor = ({ codeData, updateData }) =&amp;gt; {
    const type = codeData.type;
    const localData = codeData.data;

    if (type === "log") {
        const onMessageChange = (event) =&amp;gt; {
            localData.message = event.target.value;

            updateData(localData);
        };

        return (
            &amp;lt;div&amp;gt;
                &amp;lt;strong&amp;gt;Log:&amp;lt;/strong&amp;gt;&amp;lt;br /&amp;gt;
                &amp;lt;input name="log_message" type="text" defaultValue={localData.message} placeholder="Message" onChange={onMessageChange} /&amp;gt;
            &amp;lt;/div&amp;gt;
        );
    }

    return null;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only pattern we need to be aware of is that both components should receive the same set of properties. Of course, they should use these properties in the same way.&lt;/p&gt;

&lt;p&gt;In our example, the &lt;code&gt;codeData&lt;/code&gt; will hold the data for each component. Then, the &lt;code&gt;updateData&lt;/code&gt; property is a callback function which the dynamic components will execute when their respective data has changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Render Function
&lt;/h3&gt;

&lt;p&gt;For better context, we'll show the render function as included in its entire component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  const [activeData, setActiveData] = useState();

  const onUpdateCodeData = (data) =&amp;gt; {
    // react to data update from dynamic components
  };

  const renderPropertyEditor = () =&amp;gt; {
    if (activeData &amp;amp;&amp;amp; activeData.type !== null &amp;amp;&amp;amp; Config[activeData.type]) {
      const PropertyEditor = Config[activeData.type];
      return (&amp;lt;PropertyEditor codeData={activeData} updateData={onUpdateCodeData} /&amp;gt;);
    } else {
      return (&amp;lt;em&amp;gt;Select an element type to display.&amp;lt;/em&amp;gt;);
    }
  };

  const onDisplayAssignEditor = () =&amp;gt; {
    setActiveData({ type: "assign", data: { variable: "a", value: "100" } });
  };

  const onDisplayLogEditor = () =&amp;gt; {
    setActiveData({ type: "log", data: { message: "hello world!" } });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Toolbox&amp;lt;/h1&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;button onClick={onDisplayAssignEditor}&amp;gt;Update to ASSIGN&amp;lt;/button&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;button onClick={onDisplayLogEditor}&amp;gt;Update to LOG&amp;lt;/button&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Property Editor&amp;lt;/h1&amp;gt;
        {renderPropertyEditor()}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div &amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dynamic render function is the &lt;code&gt;renderPropertyEditor&lt;/code&gt; function. It uses the &lt;code&gt;activeData&lt;/code&gt; variable to determine which component to render.&lt;/p&gt;

&lt;p&gt;The key code in this function is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const PropertyEditor = Config[activeData.type];
return (&amp;lt;PropertyEditor codeData={activeData} updateData={onUpdateCodeData} /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this section of the code, we literally treat the functional component passed in the configuration as a stand-alone component named &lt;code&gt;PropertyEditor&lt;/code&gt;. Whatever component the &lt;code&gt;activeData.type&lt;/code&gt; value maps to, will be the one receiving the &lt;code&gt;activeData&lt;/code&gt; and &lt;code&gt;onUpdateCodeData&lt;/code&gt; properties. This will also be the same component to be rendered.&lt;/p&gt;

&lt;h2&gt;
  
  
  A More Realistic Example
&lt;/h2&gt;

&lt;p&gt;For a more real-world example, you can check out &lt;a href="https://devpinch.online/speed-build.html"&gt;Speed Build&lt;/a&gt;. It's a simple low-code app builder created using React and ReactFlow. Speed Build's code can be found &lt;a href="https://github.com/projectkenneth/react-low-code-app-builder/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The parent component and the render function can be found at &lt;code&gt;src/Editor/Canvas.js&lt;/code&gt;. Additionally, all the dynamic property components are located at the &lt;code&gt;src/PropertyPanel&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;For more similar projects that can help you learn software/web development, you can check out my &lt;a href="https://devpinch.online/"&gt;DevPinch&lt;/a&gt; initiative.&lt;/p&gt;

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

&lt;p&gt;So, that's it! We've implemented dynamic component rendering in react! &lt;/p&gt;

&lt;p&gt;Here's a quick demo:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HyDytAQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zr8yl1yspqsda4xo97jg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HyDytAQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zr8yl1yspqsda4xo97jg.gif" alt="Quick Demo"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Glad that you've reached the end of this post. Let me know what you think of this approach by sending in your comments.&lt;/p&gt;

&lt;p&gt;I hoped you learned something new from me today!&lt;/p&gt;




&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Feature Management in ReactJS</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Mon, 11 Oct 2021 10:04:46 +0000</pubDate>
      <link>https://dev.to/projectkenneth/feature-management-in-reactjs-1lgl</link>
      <guid>https://dev.to/projectkenneth/feature-management-in-reactjs-1lgl</guid>
      <description>&lt;p&gt;In this post, I'll show you how to implement feature management on your React applications. Feature management is the way to control which features are available based on certain scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do Feature Management?
&lt;/h2&gt;

&lt;p&gt;Here are some scenarios where controlling feature availability is necessary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The feature should only be turned on after a marketing event.&lt;/strong&gt; With feature flags, the feature can already be sitting in production and an administrator can just simply enable it via configuration once the event is done.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The feature should only be available to users on a specific plan.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these scenarios share the same concept. In this post, we'll focus on the 2nd one. Let's go!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Requirements
&lt;/h2&gt;

&lt;p&gt;Let's say we're building a blog application that offers the ff. features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updating Title and Content&lt;/li&gt;
&lt;li&gt;Publishing to multiple blog platforms&lt;/li&gt;
&lt;li&gt;Scheduling the publish time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's say the app offers 3 plans to users: Basic, Pro, and, Ultimate. &lt;/p&gt;

&lt;p&gt;With these plans, the team has decided to have a plan comparison table that looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Basic&lt;/th&gt;
&lt;th&gt;Pro&lt;/th&gt;
&lt;th&gt;Ultimate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Update Title and Content&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schedule the publish time ​&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publish to multiple blog platforms&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We now have all the requirements defined. Let's start building!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Starting Point
&lt;/h2&gt;

&lt;p&gt;For your reference, the initial state of the project can be found &lt;a href="https://github.com/projectkenneth/react-feature-control/tree/Initial-State"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For simplicity, we only have the &lt;code&gt;New Blog&lt;/code&gt; page in this version.&lt;/p&gt;

&lt;p&gt;The page contains the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Role Switcher to simulate changing of the plans&lt;/li&gt;
&lt;li&gt;All the features are still available to the user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how it looks like at this point:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v_6XhHDx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qmmlov1g86ni3mijnpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v_6XhHDx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qmmlov1g86ni3mijnpc.png" alt="FC-React-2"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  The Role Switcher
&lt;/h3&gt;

&lt;p&gt;Here's a look at the &lt;code&gt;RoleSwitcher&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function RoleSwitcher({ plans, activePlan, setActivePlan }) {
    const navItemTags = () =&amp;gt;
        plans.map((label, index) =&amp;gt;
            &amp;lt;li className="nav-item" key={index}&amp;gt;
                &amp;lt;button className={"nav-link" + (activePlan === index ? " active" : "")} onClick={e =&amp;gt; setActivePlan(index)}&amp;gt;{label}&amp;lt;/button&amp;gt;
            &amp;lt;/li&amp;gt;
        );

    return (
        &amp;lt;ul className="nav nav-pills"&amp;gt;
            {navItemTags()}
        &amp;lt;/ul&amp;gt;
    );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component receives 3 properties which are passed by the &lt;code&gt;App&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  const availablePlans = Config.availablePlans;
  const [activePlan, setActivePlan] = useState(0);

  &amp;lt;RoleSwitcher 
    plans={availablePlans} activePlan={activePlan} 
    setActivePlan={setActivePlan} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;App&lt;/code&gt; component then refers to the &lt;code&gt;availablePlans&lt;/code&gt; exposed by &lt;code&gt;Config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Config = {
    availablePlans: ['Basic', 'Pro', 'Ultimate']
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;RoleSwitcher&lt;/code&gt; displays all the available plans and allows the user to set the &lt;code&gt;activePlan&lt;/code&gt;. The &lt;code&gt;activePlan&lt;/code&gt; variable will then be passed to the &lt;code&gt;Editor&lt;/code&gt; component later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Feature-Based Approach
&lt;/h2&gt;

&lt;p&gt;Now, let's update the other features to only be shown on the appropriate plan.&lt;/p&gt;

&lt;p&gt;In this approach, we let the plans identify the features that are going to be available in them.&lt;/p&gt;

&lt;p&gt;Therefore, we need to make changes to the &lt;code&gt;Config&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Config = {
    availablePlans: [
        {
            id: 0,
            name: 'Basic',
            features: []
        },
        {
            id: 1,
            name: 'Pro',
            features: ['scheduledPost']
        },
        {
            id: 2,
            name: 'Ultimate',
            features: ['scheduledPost', 'multiplePublishers']
        }
    ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above change, each plan inside the &lt;code&gt;availablePlans&lt;/code&gt; array now has a list of &lt;code&gt;features&lt;/code&gt; that are available in them.&lt;/p&gt;

&lt;p&gt;Then, let's update the &lt;code&gt;RoleSwitcher&lt;/code&gt; to support this new format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function RoleSwitcher({ plans, activePlan, setActivePlan }) {
    const navItemTags = () =&amp;gt;
        plans.map((plan) =&amp;gt;
            &amp;lt;li className="nav-item" key={plan.id}&amp;gt;
                &amp;lt;button 
                    className={"nav-link" + (activePlan.id === plan.id ? " active" : "")} 
                    onClick={e =&amp;gt; setActivePlan(plan)}&amp;gt;{plan.name}&amp;lt;/button&amp;gt;
            &amp;lt;/li&amp;gt;
        );

    return (
        &amp;lt;ul className="nav nav-pills"&amp;gt;
            {navItemTags()}
        &amp;lt;/ul&amp;gt;
    );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initialization section of the &lt;code&gt;App&lt;/code&gt; component also needs to be updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const availablePlans = Config.availablePlans;
const [activePlan, setActivePlan] = useState(availablePlans[0]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, for the star of this post, let's talk about the &lt;code&gt;FeatureBlock&lt;/code&gt; component!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Feature Block Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function FeatureBlock(props) {
    const isFeatureVisible = props.activePlan.features
        .find(feature =&amp;gt; feature === props.featureName);

    if (isFeatureVisible) {
        return (
                &amp;lt;&amp;gt;
                    {props.children}
                &amp;lt;/&amp;gt;
            );
    } else {
        return null;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FeatureBlock&lt;/code&gt; component is a wrapper component and receives the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;activePlan&lt;/code&gt; property to determine the selected plan&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;featureName&lt;/code&gt; property to which will be matched against the &lt;code&gt;features&lt;/code&gt; list of the &lt;code&gt;activePlan&lt;/code&gt; property. If a match is found, the &lt;code&gt;FeatureBlock&lt;/code&gt;'s children will be rendered.&lt;/li&gt;
&lt;li&gt;The component's children which are conditionally rendered based on the above 2 properties&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For simplicity, we'll only use the &lt;code&gt;FeatureBlock&lt;/code&gt; component to wrap the publisher and scheduled inputs in the &lt;code&gt;Editor&lt;/code&gt; component. This is because the title and content fields are available to all plans anyway.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Editor&lt;/code&gt; component will now have this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Editor({ activePlan }) {
    return (
        &amp;lt;div className="col col-12"&amp;gt;
            &amp;lt;h1&amp;gt;New Post&amp;lt;/h1&amp;gt;
            &amp;lt;!--Title and content fields here--&amp;gt;
            &amp;lt;FeatureBlock activePlan={activePlan} 
                featureName="multiplePublishers"&amp;gt;
                &amp;lt;!--The publishers selection here--&amp;gt;
            &amp;lt;/FeatureBlock&amp;gt;
            &amp;lt;FeatureBlock activePlan={activePlan} 
                featureName="scheduledPost"&amp;gt;
                &amp;lt;!--The schedule input here--&amp;gt;
            &amp;lt;/FeatureBlock&amp;gt;
            &amp;lt;!--Save and submit buttons here--&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After all these changes, the &lt;code&gt;RoleSwitcher&lt;/code&gt; will now toggle the visibility of the publisher and schedule inputs.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EEqEMBH3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5kn22jl8t5qsd3lilpe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EEqEMBH3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5kn22jl8t5qsd3lilpe.gif" alt="FC-React-3"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you can see, everything is functioning as expected. But, there's a problem with the &lt;code&gt;Config&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;It's too centralized! Once the app grows, the &lt;code&gt;Config&lt;/code&gt; file has the potential to be bloated. Let's solve this in the next section.&lt;/p&gt;

&lt;p&gt;By the way, &lt;a href="https://github.com/projectkenneth/react-feature-control/blob/Feature-Based-Check"&gt;here's the code&lt;/a&gt; at this point.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Plan-Based Approach
&lt;/h2&gt;

&lt;p&gt;To solve the problem with the &lt;code&gt;Config&lt;/code&gt; file, we should follow a plan-based approach.&lt;/p&gt;

&lt;p&gt;In this approach, we're inverting the dependency. Instead of letting the plan define the features available, we let the features specify which plans they should be available on. This is a more modular and cleaner approach.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Editor&lt;/code&gt; component will now have this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Editor({ activePlan }) {
    return (
        &amp;lt;div className="col col-12"&amp;gt;
            &amp;lt;h1&amp;gt;New Post&amp;lt;/h1&amp;gt;
            &amp;lt;!--Title and content fields here--&amp;gt;
            &amp;lt;FeatureBlock activePlan={activePlan} 
                planNames={["Ultimate"]}&amp;gt;
                &amp;lt;!--The publishers selection here--&amp;gt;
            &amp;lt;/FeatureBlock&amp;gt;
            &amp;lt;FeatureBlock activePlan={activePlan} 
                planNames={["Pro", "Ultimate"]}&amp;gt;
                &amp;lt;!--The schedule input here--&amp;gt;
            &amp;lt;/FeatureBlock&amp;gt;
            &amp;lt;!--Save and submit buttons here--&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FeatureBlock&lt;/code&gt; will also be updated to support this change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function FeatureBlock(props) {
    const isFeatureVisible = props.planNames.find(plan =&amp;gt;
        plan === props.activePlan.name);

    if (isFeatureVisible) {
        return (
            &amp;lt;&amp;gt;
                {props.children}
            &amp;lt;/&amp;gt;
        );
    } else {
        return null;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the &lt;code&gt;Config&lt;/code&gt; will not be responsible for storing the plan-to-feature mappings anymore, it can already be simplified to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Config = {
    availablePlans: [
        {
            id: 0,
            name: 'Basic'
        },
        {
            id: 1,
            name: 'Pro'
        },
        {
            id: 2,
            name: 'Ultimate'
        }
    ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/projectkenneth/react-feature-control/blob/Plan-Based-Check"&gt;Here's the code&lt;/a&gt; at this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;We've successfully implemented Feature Management in React!&lt;/p&gt;

&lt;p&gt;What I've provided is simply a skeletal reference. You can expand it further to support more advanced requirements.&lt;/p&gt;

&lt;p&gt;In my case, I was thinking to implement user-specific feature availability. In this scenario, specific features can only be available to users who pass certain conditions.&lt;/p&gt;

&lt;p&gt;For example, what if only want to make the scheduled publishing feature available to users from a certain location? We'll explore this in my next article which I'll upload in the next few days!&lt;/p&gt;

&lt;p&gt;Glad that you've reached the end of this post. Let me know what you think of this approach by sending in your comments.&lt;/p&gt;

&lt;p&gt;I hoped you learned something new from me today!&lt;/p&gt;




&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Building an API using Express and MongoDB</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Fri, 01 Oct 2021 18:57:36 +0000</pubDate>
      <link>https://dev.to/projectkenneth/building-an-api-using-express-and-mongodb-3a5b</link>
      <guid>https://dev.to/projectkenneth/building-an-api-using-express-and-mongodb-3a5b</guid>
      <description>&lt;p&gt;In this post, we'll go through the process of creating an API built using Express and MongoDB.&lt;/p&gt;

&lt;p&gt;We'll cover the ff. steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up MongoDB&lt;/li&gt;
&lt;li&gt;Creating an Express application&lt;/li&gt;
&lt;li&gt;Optimizing your Express routes&lt;/li&gt;
&lt;li&gt;Handling errors&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up MongoDB
&lt;/h2&gt;

&lt;p&gt;In this section, we'll go through creating and configuring a remote MongoDB instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a MongoDB instance hosted on the cloud
&lt;/h3&gt;

&lt;p&gt;Instead of installing a local MongoDB instance, we'll use Atlas which is MongoDB's official database-as-a-service.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a MongoDB Atlas account &lt;a href="https://www.mongodb.com/cloud/atlas" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a cluster. For new accounts, you can use the &lt;strong&gt;&lt;em&gt;forever free&lt;/em&gt;&lt;/strong&gt; tier!&lt;/li&gt;
&lt;li&gt;Create the super admin user.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Managing your databases using Compass
&lt;/h3&gt;

&lt;p&gt;To better visualize our data, we'll be using the official GUI for MongoDB, Compass.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the latest &lt;strong&gt;Compass&lt;/strong&gt; version &lt;a href="https://www.mongodb.com/products/compass" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install the thing!&lt;/li&gt;
&lt;li&gt;Get the database connection string from &lt;strong&gt;Atlas&lt;/strong&gt;.

&lt;ol&gt;
&lt;li&gt;Access your &lt;strong&gt;Atlas dashboard&lt;/strong&gt;. Then, on your cluster panel, click the &lt;strong&gt;Connect&lt;/strong&gt; button. &lt;/li&gt;
&lt;li&gt;On the &lt;strong&gt;Connect&lt;/strong&gt; popup, create your super admin user.&lt;/li&gt;
&lt;li&gt;Then, for the Connection Method, choose &lt;strong&gt;Connect using MongoDB Compass&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then, choose the latest Compass version and then copy the connection string. &lt;/li&gt;
&lt;li&gt;Replace the credentials in the connection string with your actual credentials.&lt;/li&gt;
&lt;li&gt;Keep the connection string somewhere safe so you can use it in the next steps.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Launch &lt;strong&gt;Compass&lt;/strong&gt;, key in your connection string, then, click &lt;strong&gt;Connect&lt;/strong&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%2F6eicd5iojved19kugsqy.PNG" alt="DB 1.2.4 Connect to Cluster"&gt; &lt;/li&gt;

&lt;li&gt;Once connected, you can now click on the &lt;strong&gt;Create Database&lt;/strong&gt; button.&lt;/li&gt;

&lt;li&gt;Specify the database name and the first collection's name. Then, click the &lt;strong&gt;Create Database&lt;/strong&gt; button on the popup.

&lt;ol&gt;
&lt;li&gt;For this example, I created a database named &lt;code&gt;audit-log-demo&lt;/code&gt; and a collection named &lt;code&gt;user-profile&lt;/code&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%2Fl2xiw7dl44vf3uu5pyfw.PNG" alt="DB 1.2.6 Create Database"&gt; &lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;You should now see &lt;code&gt;audit-log-demo&lt;/code&gt; as part of the database list.&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Now, let's add test data to our database.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the &lt;code&gt;audit-log-demo&lt;/code&gt; database. You will be directed to the collection list page.&lt;/li&gt;
&lt;li&gt;Click on the &lt;code&gt;user-profile&lt;/code&gt; collection. You will be directed to the collection management page.&lt;/li&gt;
&lt;li&gt;Under the &lt;strong&gt;Documents&lt;/strong&gt; tab, click on the &lt;strong&gt;Add Data&lt;/strong&gt; &amp;gt; &lt;strong&gt;Insert Document&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Insert to Collection&lt;/strong&gt; popup, paste the following properties just below the &lt;strong&gt;_id&lt;/strong&gt; property:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tony"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stark"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;   
&lt;/span&gt;&lt;/code&gt;&lt;/pre&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%2F3o4n1i9m6izsx5kwn7nr.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%2F3o4n1i9m6izsx5kwn7nr.PNG" alt="DB 1.2.8.4 Collection List"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating an Express application
&lt;/h2&gt;

&lt;p&gt;In this section, let's go through the step-by-step process of creating an Express application and letting this application establish a connection to our new MongoDB instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your favorite CLI and navigate to your desired working directory.&lt;/li&gt;
&lt;li&gt;Create a new package using &lt;code&gt;npm init&lt;/code&gt;. Follow the prompts and provide the necessary details.&lt;/li&gt;
&lt;li&gt;Install both &lt;code&gt;express&lt;/code&gt; and the &lt;code&gt;mongodb&lt;/code&gt; driver by executing &lt;code&gt;npm install mongodb express --save&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the database's connection string from &lt;strong&gt;Atlas&lt;/strong&gt;.

&lt;ol&gt;
&lt;li&gt;Access your &lt;strong&gt;Atlas dashboard&lt;/strong&gt;. Then, on your cluster panel, click the &lt;strong&gt;Connect&lt;/strong&gt; button. &lt;/li&gt;
&lt;li&gt;Then, for the Connection Method, choose &lt;strong&gt;Connect your application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then, choose the appropriate NodeJS version and then copy the connection string. &lt;/li&gt;
&lt;li&gt;Replace the credentials in the connection string with your actual credentials.&lt;/li&gt;
&lt;li&gt;Keep the connection string somewhere safe so you can use it in the next steps.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Create a new environment setting with key &lt;code&gt;ALD_CONN_STRING&lt;/code&gt; and set its value to your connection string.&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Connecting to the database
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;At the root of your working directory, create an &lt;code&gt;index.js&lt;/code&gt; file with this content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ObjectId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoConnString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALD_CONN_STRING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mongoConnString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expressApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expressPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audit-log-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expressPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expressPort&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the above code, we used the &lt;code&gt;ALD_CONN_STRING&lt;/code&gt; environment variable to retrieve the connection string. Then, we instantiated the MongoDB and Express clients. We also introduced one route (&lt;code&gt;/profiles&lt;/code&gt;) which retrieves all the documents in the &lt;code&gt;user-profile&lt;/code&gt; collection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run your application by executing &lt;code&gt;node index.js&lt;/code&gt; on your CLI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then, using your favorite REST client (I'm using &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;), access the &lt;code&gt;/profiles&lt;/code&gt; endpoint of your API. You should get this result:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;GUID&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tony"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stark"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Adding a new route
&lt;/h3&gt;

&lt;p&gt;To further expand the capabilities of the API, we add a new route to get a specific profile by ID. &lt;/p&gt;

&lt;p&gt;To do this, we just need to add the following code to your &lt;code&gt;index.js&lt;/code&gt; file just before the &lt;code&gt;listen&lt;/code&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audit-log-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Checkpoint
&lt;/h3&gt;

&lt;p&gt;You can check out the &lt;code&gt;index.js&lt;/code&gt; code at this point by clicking &lt;a href="https://github.com/projectkenneth/express-mongodb-demo/tree/Initial-State" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing your Express routes
&lt;/h2&gt;

&lt;p&gt;At this stage, the 2 routes we created are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profiles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audit-log-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audit-log-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code works, but, there's one major point of improvement in them:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In both routes, the parts that connect to the database and retrieve a reference to the collection are repeated. We should always follow the DRY (Don't Repeat Yourself) principle!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how should we go about this? We introduce middleware to the code!&lt;/p&gt;

&lt;h3&gt;
  
  
  What's a middleware?
&lt;/h3&gt;

&lt;p&gt;In Express, a middleware is a function that can be executed before or after the actual request handlers.&lt;/p&gt;

&lt;p&gt;For our example, we need to define 2 middleware functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A middleware that establishes the connection to the database and will then pass this connection instance to the request handlers.&lt;/li&gt;
&lt;li&gt;A middleware that closes the connection to the database. This middleware function will be executed after the request handlers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Let's add in the middleware functions
&lt;/h3&gt;

&lt;p&gt;Here's the code for the 2 middleware functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dbConnBeforeware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoConnString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALD_CONN_STRING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mongoConnString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database connection established!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbDatabaseRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audit-log-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dbConnAfterware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database connection closed!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use them, we need to adjust the way the routes are defined to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAllProfilesHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbDatabaseRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({}).&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profileList&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProfileByIdHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbDatabaseRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// For readability, we also created 2 new separate functions for the actual request handlers&lt;/span&gt;
&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profiles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbConnBeforeware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getAllProfilesHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbConnAfterware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbConnBeforeware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getProfileByIdHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbConnAfterware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Checkpoint
&lt;/h3&gt;

&lt;p&gt;You can check out the &lt;code&gt;index.js&lt;/code&gt; code at this point by clicking &lt;a href="https://github.com/projectkenneth/express-mongodb-demo/blob/Introducing-Middlewares/index.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling errors
&lt;/h2&gt;

&lt;p&gt;Another point of improvement with the current code is error handling. &lt;/p&gt;

&lt;p&gt;If something goes wrong in the request handlers, the default Express error handler will be triggered. But, this default error handler does not close the database connection established.&lt;/p&gt;

&lt;p&gt;To fix this, we introduce our very own error handler by adding this code after the route definition section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Database connection closed!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something broke!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this custom error handler, we close the connection if any, and then log the error to the console. Lastly, we inform the API consumer that something went wrong.&lt;/p&gt;

&lt;p&gt;Now, when an error occurs, you should get this response (Postman screenshot):&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%2Fgabiypa7j5nzikgigykk.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%2Fgabiypa7j5nzikgigykk.PNG" alt="Error Handling Response"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Checkpoint
&lt;/h3&gt;

&lt;p&gt;You can check out the &lt;code&gt;index.js&lt;/code&gt; code at this point by clicking &lt;a href="https://github.com/projectkenneth/express-mongodb-demo/blob/Introduce-Error-Handling/index.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point, I added a forced error to the &lt;code&gt;getProfileByIdHandler&lt;/code&gt; handler to simulate an error happening.&lt;/p&gt;

&lt;p&gt;To view the version of the code without any of the forced errors, click &lt;a href="https://github.com/projectkenneth/express-mongodb-demo/blob/master/index.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;We've successfully created an API built on Express and MongoDB!&lt;/p&gt;

&lt;p&gt;Additionally, we've also gone through 2 rounds of code optimizations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Middleware usage&lt;/strong&gt; - for reducing code redundancy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom error handling&lt;/strong&gt; - for ensuring the database connection is closed even when issues occur&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think there are still a couple of improvements on this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Once your API grows, you should split the route definitions into multiple code files.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;dbConnBeforeware&lt;/code&gt; can also be made configurable so you can use it for other routes that handle data from another collection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What other improvements do you have in mind? And what do you think of this approach? Let me know your thoughts in the comments&lt;/p&gt;

&lt;p&gt;Glad that you've reached the end of this post. I hoped you learned something new from me today.&lt;/p&gt;




&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>api</category>
      <category>express</category>
      <category>node</category>
    </item>
    <item>
      <title>A Quick Look: The Software Architecture of Common Web App Features</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Wed, 29 Sep 2021 08:28:33 +0000</pubDate>
      <link>https://dev.to/projectkenneth/a-quick-look-the-software-architecture-of-common-web-app-features-1eno</link>
      <guid>https://dev.to/projectkenneth/a-quick-look-the-software-architecture-of-common-web-app-features-1eno</guid>
      <description>&lt;p&gt;In this post, I'll walk you through how to implement some of the most common web application features.&lt;/p&gt;

&lt;p&gt;For each feature, we'll show the ff. three details:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A real-world example as well as a description of the main challenges for the feature&lt;/li&gt;
&lt;li&gt;A list of components used in the feature&lt;/li&gt;
&lt;li&gt;Component diagram&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note though that the component list and diagram are not representative of how the real-world examples I provided were actually implemented.&lt;/p&gt;

&lt;p&gt;Lastly, the components mentioned here will be abstractions and will therefore not be attached to any specific services/platforms. This will be more of a conceptual overview.&lt;/p&gt;

&lt;p&gt;With all of that out of the way, let's start diving in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reporting
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--29ALLS5v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cf1msfvygq69zrz2sdp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--29ALLS5v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cf1msfvygq69zrz2sdp8.png" alt="Reporting - Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea of a reporting feature is to display summarized and useful information to users. In most cases, reporting features deal with tons of data. In the above screenshot from Google Analytics, all the data received from websites are summarized and presented using various graphs.&lt;/p&gt;

&lt;p&gt;The primary challenge for a reporting feature is ensuring that the summarized data loads quickly. Therefore, the process of summarizing data should be done by a different process separate from the frontend. The frontend's job is to retrieve the summarized data. Nothing more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Ingestor.&lt;/strong&gt;  This component receives all the data from all possible sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Transformer.&lt;/strong&gt; The raw data is then transformed by a separate process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reporting Database.&lt;/strong&gt; Once the data is transformed, it will then be stored in a separate reporting table/cache. This reporting table/cache will then be accessed directly by the frontend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Diagram
&lt;/h3&gt;

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

&lt;h2&gt;
  
  
  Search
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vyoXuYX2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pctbyy3pgleq6dloa05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vyoXuYX2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pctbyy3pgleq6dloa05.png" alt="Search - Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For sites with high data volume, providing a search feature is crucial. Search pages should be able to provide results quickly. For more complicated sites, search results are not just ranked by text matching but also by determining search keyword relevance as well.&lt;/p&gt;

&lt;p&gt;To achieve this, the searchable items should be indexed beforehand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Search Index.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middle Man.&lt;/strong&gt; This is the one responsible for interacting with the search index and sending over the search results to the frontend. Paginating and counting over the results should be done by this component as well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache.&lt;/strong&gt; For apps with a really large amount of data, the search results are even cached.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Diagram
&lt;/h3&gt;

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

&lt;h2&gt;
  
  
  Social Feed
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_W00D4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilmtrxo4wg2gv5q32w8f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_W00D4O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilmtrxo4wg2gv5q32w8f.jpg" alt="Social Feed - Sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A social feed basically shows a list of items relevant to a user, like text or image posts. The relevancy is usually based on two factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The closeness of the post author to the user&lt;/li&gt;
&lt;li&gt;The amount of interest the user has in the post's topic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To achieve this, feeds should be pre-calculated. Meaning, a separate and ongoing process will determine the posts that will make up a user's feed. This way, the feed items are prepared before the user even visits his/her feed page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Database.&lt;/strong&gt; Will house all the users and their relationships.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post Database.&lt;/strong&gt; Will house all the posts created by users. This database should also contain the post's topics as determined by the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed Generator.&lt;/strong&gt; The one responsible for determining and compiling the posts relevant to a user. The compiled posts will then be generated as "feed items" and will be stored in a feed database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Diagram
&lt;/h3&gt;

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

&lt;h2&gt;
  
  
  Images
&lt;/h2&gt;

&lt;p&gt;Images are not technically a full-blown feature but they should be handled properly to deliver a better user experience. &lt;/p&gt;

&lt;p&gt;For example, a user can upload a high-definition image (20MB) and, if there's no post-processing done on this original image, showing it on galleries will be a performance concern. Imagine serving a 20MB file to 1,000 users every minute. I won't do that math, but, that's not really ideal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Breakdown
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image Processor.&lt;/strong&gt; This will transform the original image into multiple versions (in different sizes) depending on what's needed by the frontend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Diagram
&lt;/h3&gt;

&lt;p&gt;In this diagram, it is assumed that the images are displayed on a gallery page showing the small version. Then, on a details page which shows a medium version of the image.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  And now, the end is near...
&lt;/h2&gt;

&lt;p&gt;I hoped you enjoyed reading this article and learned something new from me. I'd be happy to hear your thoughts so be sure to comment down below.&lt;/p&gt;




&lt;h3&gt;
  
  
  Credits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Social Feed sample photo by &lt;a href="https://unsplash.com/photos/EQSPI11rf68"&gt;dole777 from Unsplash&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>designprinciples</category>
      <category>features</category>
    </item>
    <item>
      <title>How To Break Down User Stories Into Smaller Tasks</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Tue, 28 Sep 2021 09:20:16 +0000</pubDate>
      <link>https://dev.to/projectkenneth/how-to-break-down-user-stories-into-smaller-tasks-cp0</link>
      <guid>https://dev.to/projectkenneth/how-to-break-down-user-stories-into-smaller-tasks-cp0</guid>
      <description>&lt;p&gt;In this post, I'll talk about my strategy for breaking down user stories into smaller tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a User Story?
&lt;/h2&gt;

&lt;p&gt;Before we start, let's define what user stories are. &lt;a href="https://en.wikipedia.org/wiki/User_story"&gt;A user story is an informal, natural language description of a software system feature&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;One of the common formats used for creating a user story is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a &lt;strong&gt;&amp;lt;user with this role&amp;gt;&lt;/strong&gt;, I should be able to &lt;strong&gt;&amp;lt;perform this action&amp;gt;&lt;/strong&gt; to &lt;strong&gt;&amp;lt;achieve this goal&amp;gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's look at a real-world example for a blog application:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a &lt;strong&gt;content editor&lt;/strong&gt;, I should be able to &lt;strong&gt;create a draft&lt;/strong&gt; to &lt;strong&gt;work on an article over some time&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Do I Need To Define Smaller Tasks?
&lt;/h2&gt;

&lt;p&gt;In my experience, breaking down user stories into smaller tasks can help identify common tasks that were originally spread out across multiple user stories. &lt;/p&gt;

&lt;p&gt;Remember, user stories are closer to business requirements and not technical ones.&lt;/p&gt;

&lt;p&gt;Here's a good example. Let's say that there are a couple of user stories defined to confirm with a user before proceeding with an action. When we break these user stories down, we'll discover that there's a need for a confirmation popup. Since this is a reusable component, we can better plan who will implement it and when will it be implemented.&lt;/p&gt;

&lt;p&gt;Essentially, breaking down user stories into smaller tasks allow devs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better plan their tasks, therefore, allowing them to provide more accurate estimates&lt;/li&gt;
&lt;li&gt;Have a better bug-fixing experience since issues can be mapped to each specific task instead of the larger-scoped user story&lt;/li&gt;
&lt;li&gt;Reduce duplicate work (as described in the confirmation popup scenario above)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let's Break It Down
&lt;/h2&gt;

&lt;p&gt;Now, let's work on the real-world example I gave earlier. &lt;/p&gt;

&lt;p&gt;When breaking down a user story, I first think of the following categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Pre-conditions&lt;/li&gt;
&lt;li&gt;Action&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each category can either have one or multiple tasks. Let's discuss in detail in each of their respective sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;The most important category and is even the first part of the user story. In this category, we'll answer the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who is allowed to perform the action?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The example user story is only targeted at content editors. Therefore, we need to ensure that. &lt;/p&gt;

&lt;p&gt;Since the user story is simple enough, I'll only add one task under this category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check that the user should have a &lt;strong&gt;Content Editor&lt;/strong&gt; role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more complicated systems, another consideration can be delegation. If a content editor went on leave and has assigned his/her backup editor, the check for this can be another task as well.&lt;/p&gt;

&lt;p&gt;Also, the reason why I define the security-related tasks first is that it is going to be used by all the subsequent tasks. This means, that it will be the first task I do and will be implemented as a common/reusable component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-conditions
&lt;/h3&gt;

&lt;p&gt;The tasks under this category should answer this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What needs to be done before the user can perform the action?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that these actions should only be performed after the security checks.&lt;/p&gt;

&lt;p&gt;For our example user story, the ff. tasks can be added as part of this category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check that the user already has a blog. If not, ask the user to create a blog first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In some cases, the smaller tasks here might get attached to another user story.&lt;/p&gt;

&lt;p&gt;For example, instead of "asking to create a blog", we may link to a "getting started" feature that was defined by a different user story.&lt;/p&gt;

&lt;p&gt;That doesn't mean we don't need to ensure these conditions are met first. These checks are still part of the user story.&lt;/p&gt;

&lt;h3&gt;
  
  
  Action
&lt;/h3&gt;

&lt;p&gt;Now, on to the main requirement. In this category, we answer this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can we enable the action for the user?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Additionally, we should also include validation tasks under this category.&lt;/p&gt;

&lt;p&gt;In our case, we'll add the ff. tasks under this category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;strong&gt;New Draft&lt;/strong&gt; button to the main navigation.&lt;/li&gt;
&lt;li&gt;Once the &lt;strong&gt;New Draft&lt;/strong&gt; button is clicked, display the main WYSIWYG editor.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;Save&lt;/strong&gt; button to the WYSIWYG editor.&lt;/li&gt;
&lt;li&gt;Once the &lt;strong&gt;Save&lt;/strong&gt; button is clicked, if there's content in the editor, we create a new draft record and navigate to the draft listing page.&lt;/li&gt;
&lt;li&gt;Once the &lt;strong&gt;Save&lt;/strong&gt; button is clicked, if the editor is empty, we navigate away from the editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the above tasks, everything about the WYSIWYG editor is out of scope. The kind of editor plugin or the other behaviors that should be available in it should all be considered in a separate user story. We just assume that the editor is available for integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;We've reached the end! That one-liner user story has been broken down into 7 smaller tasks.&lt;/p&gt;

&lt;p&gt;Just for a quick recap, here are the tasks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Task Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Check that the user should have a &lt;strong&gt;Content Editor&lt;/strong&gt; role.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-conditions&lt;/td&gt;
&lt;td&gt;Check that the user already has a blog. If not, ask the user to create a blog first.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;Add a &lt;strong&gt;New Draft&lt;/strong&gt; button to the main navigation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;Once the &lt;strong&gt;New Draft&lt;/strong&gt; button is clicked, display the main WYSIWYG editor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;Add a &lt;strong&gt;Save&lt;/strong&gt; button to the WYSIWYG editor.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;Once the &lt;strong&gt;Save&lt;/strong&gt; button is clicked, if there's content in the editor, we create a new draft record and navigate to the draft listing page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;Once the &lt;strong&gt;Save&lt;/strong&gt; button is clicked, if the editor is empty, we navigate away from the editor.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Again, breaking down user stories into smaller tasks enables better task planning and management. It is a necessary step for devs. &lt;/p&gt;

&lt;p&gt;Also, there are other approaches to doing this. If you happen to know one, I'd love to hear from you so, share your thoughts in the comments below!&lt;/p&gt;




&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>agile</category>
      <category>development</category>
      <category>planning</category>
    </item>
    <item>
      <title>Modular Routing in React</title>
      <dc:creator>Kenneth Angelo Reyes</dc:creator>
      <pubDate>Mon, 27 Sep 2021 15:48:01 +0000</pubDate>
      <link>https://dev.to/projectkenneth/modular-routing-in-react-2ab1</link>
      <guid>https://dev.to/projectkenneth/modular-routing-in-react-2ab1</guid>
      <description>&lt;p&gt;In a React + React Router environment, routing configuration is a one-to-one mapping between a route and that route's display elements.&lt;/p&gt;

&lt;p&gt;Here's a basic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Route exact path='/' component={Home} /&amp;gt;
&amp;lt;Route exact path='/drafts' component={DraftListing} /&amp;gt;
&amp;lt;Route path='/drafts/:draftId' component={DraftUpdate} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above approach is suitable for simple applications, but, for complex ones, it's not really ideal.&lt;/p&gt;

&lt;p&gt;Complex applications are usually composed of several modules. Each module is then composed of several components. If this is the application's structure, it is just reasonable for the routing model to follow the same structure, right?&lt;/p&gt;

&lt;p&gt;Well, that's just what we're going to do! In this post, let's look at implementing modular routing in React.&lt;/p&gt;

&lt;p&gt;We're doing this in 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup a theoretical application and identify its modules and components&lt;/li&gt;
&lt;li&gt;Implement a regular routing model for the said application&lt;/li&gt;
&lt;li&gt;Transform the regular routing model into a modular one&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Application, the Modules, and the Components
&lt;/h2&gt;

&lt;p&gt;Let's say we're building a blog-writing application and we have decided to implement the ff. modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post Management&lt;/li&gt;
&lt;li&gt;Draft Management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given the above modules, we'll probably design the routing map like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Post Management&lt;/td&gt;
&lt;td&gt;/posts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Draft Management&lt;/td&gt;
&lt;td&gt;/drafts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Looking at the above routings, it seems like we're only going to have 3 components directly representing each of our main modules. But, we all know that these modules are still going to be composed of one or more components. &lt;/p&gt;

&lt;p&gt;In fact, we can even argue that these modules are "smaller applications" themselves. For instance, &lt;em&gt;Post Management&lt;/em&gt; should also have a route navigating to the &lt;em&gt;Update Post&lt;/em&gt; component. &lt;em&gt;Draft Management&lt;/em&gt; should have this behavior as well (navigate to the &lt;em&gt;Update Draft&lt;/em&gt; component).&lt;/p&gt;

&lt;p&gt;So, what do we do now? We "push up" the concept of modules and identify the actual components of the application.&lt;/p&gt;

&lt;p&gt;Here's the new routing map but with an added &lt;em&gt;Component&lt;/em&gt; column.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Post Management&lt;/td&gt;
&lt;td&gt;Post Listing&lt;/td&gt;
&lt;td&gt;/posts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Update Post&lt;/td&gt;
&lt;td&gt;/posts/:postId&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Draft Management&lt;/td&gt;
&lt;td&gt;Draft Listing&lt;/td&gt;
&lt;td&gt;/drafts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Update Draft&lt;/td&gt;
&lt;td&gt;/drafts/:draftId&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Regular Routing Approach
&lt;/h2&gt;

&lt;p&gt;Now, we have identified the modules and components for our application. Let's go ahead and implement them!&lt;/p&gt;

&lt;h3&gt;
  
  
  Create A New React App First
&lt;/h3&gt;

&lt;p&gt;Of course, the first step is to create a brand new React application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app reactjs-module-based-routing
cd reactjs-module-based-routing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we'll install the &lt;a href="https://reactrouter.com/web/guides/quick-start" rel="noopener noreferrer"&gt;React Router for Web Applications library&lt;/a&gt; since we're building a web application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simplicity, we remove all of the other files under the &lt;code&gt;/src&lt;/code&gt; directory. &lt;/p&gt;

&lt;p&gt;Then, we create a new &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a new &lt;code&gt;App.js&lt;/code&gt; as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  return (
    &amp;lt;div&amp;gt;

    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the code at this point &lt;a href="https://github.com/projectkenneth/reactjs-module-based-routing/tree/Initial-State" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create The Components
&lt;/h3&gt;

&lt;p&gt;For better maintainability, the components should be grouped by their module. So, we'll have one directory per module and each of these directories will only contain the components relevant to their respective module.&lt;/p&gt;

&lt;p&gt;Just to recap, we'll need to create the components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Draft Listing&lt;/li&gt;
&lt;li&gt;Draft Update&lt;/li&gt;
&lt;li&gt;Post Listing&lt;/li&gt;
&lt;li&gt;Post Update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, we'll need to create a Home component as well just so we can render a homepage.&lt;/p&gt;

&lt;p&gt;For the Draft and Post Update components, we will use the &lt;code&gt;useParams&lt;/code&gt; function from &lt;code&gt;react-router-dom&lt;/code&gt; to get the draft or post ID passed in the URL.&lt;/p&gt;

&lt;p&gt;Here's how the Draft Update component looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useParams } from 'react-router-dom';

function DraftUpdate() {
    let { draftId } = useParams();

    return (
        &amp;lt;h1&amp;gt;This is Draft Update: {draftId}&amp;lt;/h1&amp;gt;
    );
}

export default DraftUpdate;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the Draft and Post Listing components, we will use the Link component from &lt;code&gt;react-router-dom&lt;/code&gt; to render links to fake drafts or posts.&lt;/p&gt;

&lt;p&gt;Here's how the Draft Listing component looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Link } from 'react-router-dom';

function DraftListing() {
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;This is Draft Listing&amp;lt;/h1&amp;gt;
            &amp;lt;ul&amp;gt;
                &amp;lt;li&amp;gt;&amp;lt;Link to='/drafts/1'&amp;gt;Draft 1&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
                &amp;lt;li&amp;gt;&amp;lt;Link to='/drafts/2'&amp;gt;Draft 2&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}

export default DraftListing;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check out how the code looks like at this point &lt;a href="https://github.com/projectkenneth/reactjs-module-based-routing/tree/Added-components" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create The Initial Routing
&lt;/h3&gt;

&lt;p&gt;Now, onto the actual routing. We'll need to add the ff. code to the &lt;code&gt;App&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;BrowserRouter&amp;gt;
  &amp;lt;nav&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;Link to='/'&amp;gt;Home&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;Link to='/drafts'&amp;gt;Drafts&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;Link to='/posts'&amp;gt;Posts&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/nav&amp;gt;
  &amp;lt;Switch&amp;gt;
    &amp;lt;Route exact path='/' component={Home} /&amp;gt;
    &amp;lt;Route exact path='/drafts' component={DraftListing} /&amp;gt;
    &amp;lt;Route exact path='/posts' component={PostListing} /&amp;gt;
  &amp;lt;/Switch&amp;gt;
&amp;lt;/BrowserRouter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the updated &lt;code&gt;App&lt;/code&gt; code, we now have a navigation section, and the routes to the Homepage, Draft Listing, and Post Listing have been defined.&lt;/p&gt;

&lt;p&gt;Now, how should we add the routes to the draft and post update components?&lt;/p&gt;

&lt;p&gt;We can do this by updating the &lt;code&gt;Switch&lt;/code&gt; section of the &lt;code&gt;App&lt;/code&gt; component code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Switch&amp;gt;
  &amp;lt;Route exact path='/' component={Home} /&amp;gt;
  &amp;lt;Route exact path='/drafts' component={DraftListing} /&amp;gt;
  &amp;lt;Route path='/drafts/:draftId' component={DraftUpdate} /&amp;gt;
  &amp;lt;Route exact path='/posts' component={PostListing} /&amp;gt;
  &amp;lt;Route path='/posts/:postId' component={PostUpdate} /&amp;gt;
&amp;lt;/Switch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically, the above approach will already work. But, there's actually a couple of issues here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The references to the route names are scattered across the files which makes the project hard to maintain. For example, the path &lt;code&gt;drafts&lt;/code&gt; can be found in both the &lt;code&gt;App&lt;/code&gt; and &lt;code&gt;DraftListing&lt;/code&gt; components. If we want to change this path, we'd have to update both files.&lt;/li&gt;
&lt;li&gt;The routing for the Draft Management and Post Management module are mixed up together in one file. Essentially defeating the purpose of defining modules in the first place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before moving to the next section, you can check out what the code looks like at this point &lt;a href="https://github.com/projectkenneth/reactjs-module-based-routing/blob/Initial-Routing-Configuration" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transforming to Modular Routing
&lt;/h2&gt;

&lt;p&gt;To address the issues I mentioned, we have to consider one very important thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Modules should be stand-alone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Modules should be treated as smaller applications inside a larger one. They have to be in charge of everything related to them and that includes routing. This means that we should detach a module's routing configuration from the &lt;code&gt;App&lt;/code&gt; component and place the configuration inside its respective module.&lt;/p&gt;

&lt;p&gt;To do this, we need to introduce &lt;em&gt;Module Routers&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Routers
&lt;/h3&gt;

&lt;p&gt;A module router, as its name suggests, handles all the routing for a module. For this example, &lt;code&gt;Module Routers&lt;/code&gt; are special components.&lt;/p&gt;

&lt;p&gt;Before creating the module router we first need to update the current routing configuration.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;App&lt;/code&gt; component, instead of directly specifying the routes to the Draft Management components, we now do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// From these
&amp;lt;Switch&amp;gt;
    &amp;lt;Route exact path='/drafts' component={DraftListing} /&amp;gt;
    &amp;lt;Route path='/drafts/:draftId' component={DraftUpdate} /&amp;gt;
&amp;lt;/Switch&amp;gt;

// To these
&amp;lt;Switch&amp;gt;
  &amp;lt;Route path='/drafts' component={DraftRouter} /&amp;gt;
&amp;lt;/Switch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, what we're doing here is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All routing that starts with the path &lt;code&gt;/drafts&lt;/code&gt; will be handled by the &lt;code&gt;DraftRouter&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We then create the actual &lt;code&gt;DraftRouter&lt;/code&gt; component. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function DraftRouter() {
    let { path } = useRouteMatch();

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;strong&amp;gt;You are in draft management&amp;lt;/strong&amp;gt;
            &amp;lt;Switch&amp;gt;
                &amp;lt;Route exact path={path}&amp;gt;
                    &amp;lt;DraftListing modulePath={path} /&amp;gt;
                &amp;lt;/Route&amp;gt;
                &amp;lt;Route path={`${path}/:draftId`} component={DraftUpdate} /&amp;gt;
            &amp;lt;/Switch&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what's happening inside the &lt;code&gt;DraftRouter&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;useRouteMatch&lt;/code&gt; function to get the current route path. This way, we don't have to hardcode the phrase &lt;code&gt;drafts&lt;/code&gt; and it will only be defined in the &lt;code&gt;App&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;We then defined a couple of sub-routes. If we received only the &lt;code&gt;/drafts&lt;/code&gt; path, we'll render the &lt;code&gt;DraftListing&lt;/code&gt; component. If we received the draft ID path, we render the &lt;code&gt;DraftUpdate&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, you may have noticed the &lt;code&gt;modulePath&lt;/code&gt; property of the &lt;code&gt;DraftListing&lt;/code&gt; component. This is because, at this point, we've updated the &lt;code&gt;DraftListing&lt;/code&gt; component to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function DraftListing(props) {
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;This is Draft Listing&amp;lt;/h1&amp;gt;
            &amp;lt;ul&amp;gt;
                &amp;lt;li&amp;gt;&amp;lt;Link to={`${props.modulePath}/1`}&amp;gt;Draft 1&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
                &amp;lt;li&amp;gt;&amp;lt;Link to={`${props.modulePath}/2`}&amp;gt;Draft 2&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we used the &lt;code&gt;modulePath&lt;/code&gt; property to dynamically inject the &lt;code&gt;/drafts&lt;/code&gt; path. There's no need to hardcode that path in this component as well.&lt;/p&gt;

&lt;p&gt;I've also updated the Post Management module to follow this approach. &lt;/p&gt;

&lt;p&gt;To check out the final state of the code, click &lt;a href="https://github.com/projectkenneth/reactjs-module-based-routing/tree/Hello-Module-Routers/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So, that's it! We've successfully implemented modular routing in React.&lt;/p&gt;

&lt;p&gt;At this stage, our &lt;code&gt;src&lt;/code&gt; directory looks 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%2F1dh5qrtwc2pjzy4mn50l.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%2F1dh5qrtwc2pjzy4mn50l.png" alt="wAWv1K2D2"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;With this approach, we can now enjoy the ff. benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If we need to change a module's root path, we just need to change it in one place, in the &lt;code&gt;App&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;If we need to remove/disable a module, we can simply remove its routing configuration from the &lt;code&gt;App&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;The routes are easier to maintain since each module has its own configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyway, I hoped you learned something new from me today. Let me know your thoughts in the comments!&lt;/p&gt;




&lt;p&gt;Hey, you! Follow me on &lt;a href="https://twitter.com/projectkenneth" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
