<?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>Forem: Dillibe Chisom Okorie</title>
    <description>The latest articles on Forem by Dillibe Chisom Okorie (@dillibe).</description>
    <link>https://forem.com/dillibe</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%2F3760353%2F9321e315-c7cb-40ac-b048-3f419b08632d.jpg</url>
      <title>Forem: Dillibe Chisom Okorie</title>
      <link>https://forem.com/dillibe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dillibe"/>
    <language>en</language>
    <item>
      <title>How I Finally Secured My impextech Node.js API (Without Losing My Mind to TypeScript) 🛡️</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Mon, 06 Apr 2026 00:34:30 +0000</pubDate>
      <link>https://forem.com/dillibe/how-i-finally-secured-my-impextech-nodejs-api-without-losing-my-mind-to-typescript-3f1n</link>
      <guid>https://forem.com/dillibe/how-i-finally-secured-my-impextech-nodejs-api-without-losing-my-mind-to-typescript-3f1n</guid>
      <description>&lt;p&gt;Let's be honest: building an API that "works on my machine" is a great feeling. But moving from an API that simply returns data to one that is actually secure, type-safe, and documented? That’s a whole different beast.&lt;/p&gt;

&lt;p&gt;I am currently transitioning from medicine (I'm an MD) to backend engineering, and I’ve been building a gadget e-commerce engine called impextech. After finishing my unit tests and getting the MongoDB data layer working, I hit a wall.&lt;/p&gt;

&lt;p&gt;My authentication logic was messy. My controllers were getting bloated. And testing my protected routes in Postman was driving me crazy.&lt;/p&gt;

&lt;p&gt;Here is exactly how I cleaned up the mess, locked down my routes, and saved my sanity using &lt;code&gt;express-jwt&lt;/code&gt;, TypeScript Generics, and Swagger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Stopping the Copy-Paste Madness (JWT Middleware)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally, I was manually verifying JWTs inside my route handlers. If a user wanted to add a product, I’d check the header, decode the token, check their role... you know the drill. It was repetitive and prone to errors.&lt;/p&gt;

&lt;p&gt;I finally removed all of that out and set up a proper middleware chain using &lt;code&gt;express-jwt&lt;/code&gt;. I created a "Gate" that automatically handles the decryption, and then built a specific "VIP Checkpoint" for my admin routes.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt; &lt;span class="o"&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;JWTRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TokenPayload&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&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="nx"&gt;NextFunction&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;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;auth&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&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="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;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access denied. Admins only.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;   

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

&lt;/div&gt;



&lt;p&gt;Now, my route file is incredibly clean: &lt;code&gt;router.post('/add', requireLogin, isAdmin, createProduct);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The TypeScript "Aha!" Moment 💡&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you write standard JavaScript, attaching user data to a request object is easy: &lt;code&gt;req.user = decodedToken&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But if you use TypeScript, you know the pain I ran into next. The compiler started screaming at me because standard Express &lt;code&gt;Request&lt;/code&gt; objects don't have an &lt;code&gt;auth&lt;/code&gt; or &lt;code&gt;user&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The temptation to just slap an &lt;code&gt;any&lt;/code&gt; type on the request and move on was huge. But I forced myself to dig into Generics (&lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;) instead.&lt;/p&gt;

&lt;p&gt;I defined exactly what my token payload looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TokenPayload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Then, I mapped it to the request: &lt;code&gt;JWTRequest&amp;lt;TokenPayload&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Suddenly, my IDE knew exactly what was inside req.auth. No more undefined property errors. The compiler now enforces my role-based access before a single line of business logic executes. Getting that autocomplete popup in VS Code for req.auth.role was one of the most satisfying moments of this project.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;3. Putting the API on a Diet (The Service Layer)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I added more security, my controllers were getting fat. They were handling HTTP status codes, parsing body data, and trying to do database lookups.&lt;/p&gt;

&lt;p&gt;I decided to implement a &lt;strong&gt;Service Layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I split the codebase so that my Controllers only handle the web logic (req/res), and my Services handle the heavy lifting (database queries, business rules, password hashing).&lt;/p&gt;

&lt;p&gt;If I ever want to write a background script to update inventory, I don't have to mock an HTTP request. I can just call the Service directly. It made the whole engine drastically easier to reason about&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Throwing out my Postman Tabs (Enter Swagger)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing a secure API is great, but testing protected routes blindly is a nightmare. I was getting so tired of manually copying tokens, opening Postman, pasting them into the Authorization header, and hoping I didn't miss a character.&lt;/p&gt;

&lt;p&gt;I took the time to integrate Swagger (OpenAPI).&lt;/p&gt;

&lt;p&gt;Instead of guessing what my endpoints need, I now have an interactive UI. I can log in once, click the little "Authorize" padlock, paste my token, and instantly test any protected route directly from my browser.&lt;/p&gt;

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

&lt;p&gt;In medicine, we use patient charts so every doctor knows exactly what's happening. Swagger is basically the medical chart for my API. It keeps everything readable and testable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Moving from "it works" to "it's structured" is painful but worth it. By combining Type-Safe middleware with auto-generated documentation, the foundation of my engine is finally solid. Next up: finishing the CRUD operations and getting this thing connected to a frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you guys handle your route protection?&lt;/strong&gt; Do you roll your own middleware or lean on heavier packages like Passport? Let me know in the comments&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>webdev</category>
      <category>express</category>
    </item>
    <item>
      <title>How I Built a Robust Testing Suite for a Node.js API: A Guide to Data Integrity</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Sun, 22 Mar 2026 07:39:18 +0000</pubDate>
      <link>https://forem.com/dillibe/how-i-built-a-robust-testing-suite-for-a-nodejs-api-a-guide-to-data-integrity-10nh</link>
      <guid>https://forem.com/dillibe/how-i-built-a-robust-testing-suite-for-a-nodejs-api-a-guide-to-data-integrity-10nh</guid>
      <description>&lt;p&gt;Building a backend requires a disciplined approach to data modeling. If your schema relationships aren't validated correctly, the entire application logic becomes fragile during high-traffic operations.&lt;/p&gt;

&lt;p&gt;For my latest project, Impextech, I implemented a professional-grade testing environment to move past manual verification. Here is a breakdown of how I used &lt;strong&gt;Jest&lt;/strong&gt; and &lt;strong&gt;MongoDB Memory Server&lt;/strong&gt; to ensure my data layer is bulletproof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Virtual Database" Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn't want my tests polluting my production database. By using &lt;code&gt;mongodb-memory-server&lt;/code&gt;, I created a virtual database in RAM that resets after every test execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;beforeAll&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;mongoServer&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;MongoMemoryServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6.0.4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mongoose&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;mongoServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUri&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;&lt;strong&gt;Lesson Learned: The "Naming Conflict"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During development, I hit a path-resolution error. My test was looking for &lt;code&gt;user&lt;/code&gt; but my schema used &lt;code&gt;user_id&lt;/code&gt;. TypeScript caught the mismatch, but it was the Unit Test that proved the validation logic was failing because of it.&lt;/p&gt;

&lt;p&gt;I’ve now aligned all models (Orders, Payments, Carts) to use consistent snake_case naming that mirrors the production API requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I'm Testing Everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unit testing isn't just about finding bugs; it's about &lt;strong&gt;Defensive Design&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Ensuring &lt;code&gt;quantity&lt;/code&gt; can't be less than 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integrity&lt;/strong&gt;: Trimming whitespace from emails automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Constraints&lt;/strong&gt;: Blocking unapproved payment methods via Enums.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With 22 green checkmarks in my terminal, the Impextech engine is officially ready for the next phase of API development.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuzjos4mhye547u3ptpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuzjos4mhye547u3ptpn.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Technical Reflection: Building the Impextech Database Architecture 🏗️</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Mon, 09 Mar 2026 14:28:32 +0000</pubDate>
      <link>https://forem.com/dillibe/technical-reflection-building-the-impextech-database-architecture-5d7k</link>
      <guid>https://forem.com/dillibe/technical-reflection-building-the-impextech-database-architecture-5d7k</guid>
      <description>&lt;p&gt;The completion of the data modeling phase for Impextech represents a significant shift from standard JavaScript scripting to robust, type-safe backend engineering. Here is a breakdown of the architectural decisions and technical milestones achieved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Implementing Strict Type Safety (TypeScript)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary goal for this phase was to eliminate runtime data errors by moving to &lt;strong&gt;TypeScript&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schema Inference&lt;/strong&gt;: Instead of manually maintaining separate interfaces and schemas, I utilized Mongoose's &lt;code&gt;InferSchemaType&lt;/code&gt;. This ensures that the TypeScript compiler and the MongoDB validation rules are always in sync, providing 100% type coverage for our product and user data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IDE Support&lt;/strong&gt;: This transition has significantly improved the development experience, offering real-time autocomplete and catching property mismatch bugs before they ever reach the execution phase.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Migration to ES Modules (ESM)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I successfully migrated the project from the legacy CommonJS (&lt;code&gt;require&lt;/code&gt;) system to modern ES Modules (&lt;code&gt;import/export&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Named Imports&lt;/strong&gt;: By using named imports for Mongoose components, the codebase is now cleaner and optimized for tree-shaking, which reduces the application's overall memory footprint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modern Standards&lt;/strong&gt;: Aligning with ESM ensures that Impextech is compatible with the latest Node.js performance updates and industry-standard module resolution patterns.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Collaboration and Configuration Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Configuration is often the most challenging part of a TypeScript migration. When I encountered complex module resolution errors, I reached out to a &lt;strong&gt;fellow Backend Engineer&lt;/strong&gt; for a code review.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;tsconfig.json Evaluation&lt;/strong&gt;: Through this collaboration, we optimized the tsconfig.json file—specifically the &lt;code&gt;moduleResolution&lt;/code&gt; and &lt;code&gt;target settings&lt;/code&gt; to ensure seamless integration between the TypeScript compiler and the Node.js runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Key Takeaway&lt;/strong&gt;: This experience reinforced the value of peer review and technical collaboration in resolving infrastructure bottlenecks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Version Control &amp;amp; Git Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To maintain a stable production environment, I implemented a dedicated branching strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feature Branching&lt;/strong&gt;: All model development was conducted on a &lt;code&gt;design-models&lt;/code&gt; branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Once the schemas were validated and the build scripts were passing, the branch was merged into &lt;code&gt;main&lt;/code&gt;, ensuring a clean, documented history of the project's evolution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Current Project Status&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: MongoDB Atlas Connectivity Verified ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: TypeScript/ESM Pipeline Stabilized ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Models&lt;/strong&gt;: Product and User Blueprints Finalized ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Steps&lt;/strong&gt;: Developing the Controller layer and RESTful API routes to handle business logic and data flow.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building Yarncom: From 0 to 22 Passing Integration Tests in 6 Days 🚀</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Wed, 25 Feb 2026 20:56:48 +0000</pubDate>
      <link>https://forem.com/dillibe/building-yarncom-from-0-to-22-passing-integration-tests-in-6-days-137</link>
      <guid>https://forem.com/dillibe/building-yarncom-from-0-to-22-passing-integration-tests-in-6-days-137</guid>
      <description>&lt;p&gt;Building a production-ready API from scratch is a rite of passage for every backend engineer. For my AltSchool Africa exam, I spent the last week building Yarncom — a secure, community-driven blogging engine.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of the architecture, the logic, and the environment "ghosts" I had to bust to get to a green terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Architecture: MVC and State Logic
&lt;/h2&gt;

&lt;p&gt;To keep the system maintainable, I implemented a strict Model-View-Controller (MVC) pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Models&lt;/strong&gt;: Defined with Mongoose to handle complex schemas, including an Author reference that links Blogs to Users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt;: The "brains" of the engine, managing the data flow and handling asynchronous handshakes with MongoDB.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Machine&lt;/strong&gt;: Articles transition between &lt;code&gt;draft&lt;/code&gt; and &lt;code&gt;published&lt;/code&gt; states. I implemented security guards to ensure drafts remain private while published content hits the public feed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Automation with Mongoose Hooks
&lt;/h3&gt;

&lt;p&gt;One of the most satisfying features was building an automated Reading Time Algorithm. Using a Mongoose &lt;code&gt;pre-save&lt;/code&gt; hook, the engine analyzes the word count of the body text and calculates the estimate before the document is even saved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blogSchema.pre('save', async function() {
    if (this.body) {
        const wordsPerMinute = 200;
        const words = this.body.split(/\s+/).length;
        this.reading_time = Math.ceil(words / wordsPerMinute);
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Stateless Security with JWT
&lt;/h2&gt;

&lt;p&gt;I moved away from traditional sessions for this build, opting for JSON Web Tokens (JWT) stored in HTTP-only cookies.&lt;/p&gt;

&lt;p&gt;This setup provides a stateless authentication layer that is both secure and scalable. The middleware checks for the token on every protected route, verifying the digital signature against a hidden JWT_SECRET before allowing the request to proceed to the controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Troubleshooting the "Ghosts"
&lt;/h2&gt;

&lt;p&gt;In the journey to production, I encountered two specific bottlenecks that taught me more about systems than any documentation could:&lt;/p&gt;

&lt;h3&gt;
  
  
  The AirPlay Port Conflict (Port 5000)
&lt;/h3&gt;

&lt;p&gt;I spent considerable time debugging a persistent 404 error where my server appeared to be running, but Postman couldn't find my routes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Discovery&lt;/strong&gt;: macOS Monterey uses Port 5000 for the AirPlay Receiver.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Fix&lt;/strong&gt;: Migrating the local environment to Port 3000 resolved the conflict instantly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing Isolation (Duplicate Keys)
&lt;/h3&gt;

&lt;p&gt;While writing automated tests with Jest, I hit &lt;code&gt;E11000&lt;/code&gt; duplicate key errors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: I implemented "Unique Data Assets" for the test suite, using timestamps (&lt;code&gt;Date.now()&lt;/code&gt;) for user emails to ensure every test run had a clean, isolated database timeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Quality Assurance: 22 Integration Tests
&lt;/h2&gt;

&lt;p&gt;I didn't consider the project finished until the logic was bulletproof. Using &lt;code&gt;Jest&lt;/code&gt; and &lt;code&gt;Supertest&lt;/code&gt;, I wrote a comprehensive suite of 22 tests covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Auth handshakes (Signup/Login/Logout).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search and Regex accuracy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Authorization checks (Ensuring User B cannot delete User A's work).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read-count incrementation metrics.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Live Deployment
&lt;/h2&gt;

&lt;p&gt;The final build is officially live on Render, connected to a MongoDB Atlas cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links:
&lt;/h3&gt;

&lt;p&gt;GitHub Repository:  &lt;a href="https://github.com/dillibs001/yarncom-api" rel="noopener noreferrer"&gt;Yarncom github repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live Demo: &lt;a href="https://yarncom-api.onrender.com/blogs$0" rel="noopener noreferrer"&gt;Yarncom demo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This project wasn't just about passing an exam; it was about mastering Systems Design and Environment Awareness. Building Yarncom proved that a robust backend isn't just written but built  through persistence and rigorous testing.&lt;/p&gt;

&lt;p&gt;Onward to the next build!&lt;/p&gt;

&lt;h1&gt;
  
  
  backend #node #javascript #mongodb #webdev #tutorial
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Why Your Mongoose Hook is Returning 0 (The 'this' Lesson)</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Fri, 13 Feb 2026 00:29:46 +0000</pubDate>
      <link>https://forem.com/dillibe/why-your-mongoose-hook-is-returning-0-the-this-lesson-4gjj</link>
      <guid>https://forem.com/dillibe/why-your-mongoose-hook-is-returning-0-the-this-lesson-4gjj</guid>
      <description>&lt;h3&gt;
  
  
  Building Yarncom Phase 2: Automation, Word Counts, and the "Arrow Function" Trap
&lt;/h3&gt;

&lt;p&gt;I’m currently on Day 2 of building &lt;strong&gt;Yarncom&lt;/strong&gt;, a community-driven blogging API. Yesterday, I handled the Security Handshake. Today, I faced the Logic Layer.&lt;br&gt;
The goal was simple; Whenever a user saves a blog post, the API should automatically calculate the &lt;strong&gt;Estimated Reading Time&lt;/strong&gt; based on a 200-words-per-minute average.&lt;br&gt;
Here is the technical breakdown of the challenges I faced and the code that solved them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Automation Logic (The Pre-Save Hook)&lt;/strong&gt;&lt;br&gt;
Instead of forcing the user to tell us how long their post is, I used a Mongoose &lt;code&gt;pre-save&lt;/code&gt; hook. This is a function that runs after the data is sent but before it’s persisted in the database.&lt;br&gt;
&lt;code&gt;blogSchema.pre('save', async function() {&lt;br&gt;
    if (this.body) {&lt;br&gt;
        const wordsPerMinute = 200;&lt;br&gt;
        const words = this.body.split(/\s+/).length;&lt;br&gt;
        this.reading_time = Math.ceil(words / wordsPerMinute);&lt;br&gt;
        console.log( Calculated: ${this.reading_time} min);&lt;br&gt;
    }&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Trap: Arrow Functions vs. Regular Functions&lt;/strong&gt;&lt;br&gt;
This is where I got stuck. I initially used an Arrow Function: &lt;code&gt;async () =&amp;gt; { ... }&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;The Problem&lt;/strong&gt;: Arrow functions do not bind their own &lt;code&gt;this&lt;/code&gt;. In Mongoose, this needs to point to the Document being saved. Because I used an arrow, &lt;code&gt;this.body&lt;/code&gt; was undefined, and my terminal was silent.&lt;br&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: Always use a regular &lt;code&gt;function()&lt;/code&gt; in Mongoose hooks if you need to access the data. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cleaning up the "Next" Callback&lt;/strong&gt;&lt;br&gt;
I encountered the "next is not a function" error. This usually happens when you try to call a callback that isn't provided in an async context. By switching to a pure async function for my hook, I removed the need for the &lt;code&gt;next()&lt;/code&gt; entirely. Mongoose is smart enough to wait for the &lt;code&gt;Promise&lt;/code&gt; to resolve before moving to the save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Result in Postman&lt;/strong&gt;&lt;br&gt;
After a few "failed renders," I finally got that beautiful 201 Created status. The response now includes:&lt;br&gt;
&lt;code&gt;"reading_time": 1&lt;/code&gt;&lt;code&gt;"message": "Yarn successfully spun!"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backend engineering is as much about &lt;strong&gt;Environment Awareness&lt;/strong&gt; as it is about syntax. You have to know where your &lt;code&gt;this&lt;/code&gt; is pointing and who is holding the "Baton" in the middleware chain.&lt;/p&gt;

&lt;h1&gt;
  
  
  node #javascript #mongodb #webdev #tutorial
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Why Your Mongoose Hook is Returning 0 (The 'this' Lesson)</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Fri, 13 Feb 2026 00:29:46 +0000</pubDate>
      <link>https://forem.com/dillibe/why-your-mongoose-hook-is-returning-0-the-this-lesson-2126</link>
      <guid>https://forem.com/dillibe/why-your-mongoose-hook-is-returning-0-the-this-lesson-2126</guid>
      <description>&lt;h3&gt;
  
  
  Building Yarncom Phase 2: Automation, Word Counts, and the "Arrow Function" Trap
&lt;/h3&gt;

&lt;p&gt;I’m currently on Day 2 of building &lt;strong&gt;Yarncom&lt;/strong&gt;, a community-driven blogging API. Yesterday, I handled the Security Handshake. Today, I faced the Logic Layer.&lt;br&gt;
The goal was simple; Whenever a user saves a blog post, the API should automatically calculate the &lt;strong&gt;Estimated Reading Time&lt;/strong&gt; based on a 200-words-per-minute average.&lt;br&gt;
Here is the technical breakdown of the challenges I faced and the code that solved them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Automation Logic (The Pre-Save Hook)&lt;/strong&gt;&lt;br&gt;
Instead of forcing the user to tell us how long their post is, I used a Mongoose &lt;code&gt;pre-save&lt;/code&gt; hook. This is a function that runs after the data is sent but before it’s persisted in the database.&lt;br&gt;
&lt;code&gt;blogSchema.pre('save', async function() {&lt;br&gt;
    if (this.body) {&lt;br&gt;
        const wordsPerMinute = 200;&lt;br&gt;
        const words = this.body.split(/\s+/).length;&lt;br&gt;
        this.reading_time = Math.ceil(words / wordsPerMinute);&lt;br&gt;
        console.log( Calculated: ${this.reading_time} min);&lt;br&gt;
    }&lt;br&gt;
});&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Trap: Arrow Functions vs. Regular Functions&lt;/strong&gt;&lt;br&gt;
This is where I got stuck. I initially used an Arrow Function: &lt;code&gt;async () =&amp;gt; { ... }&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;The Problem&lt;/strong&gt;: Arrow functions do not bind their own &lt;code&gt;this&lt;/code&gt;. In Mongoose, this needs to point to the Document being saved. Because I used an arrow, &lt;code&gt;this.body&lt;/code&gt; was undefined, and my terminal was silent.&lt;br&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: Always use a regular &lt;code&gt;function()&lt;/code&gt; in Mongoose hooks if you need to access the data. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cleaning up the "Next" Callback&lt;/strong&gt;&lt;br&gt;
I encountered the "next is not a function" error. This usually happens when you try to call a callback that isn't provided in an async context. By switching to a pure async function for my hook, I removed the need for the &lt;code&gt;next()&lt;/code&gt; entirely. Mongoose is smart enough to wait for the &lt;code&gt;Promise&lt;/code&gt; to resolve before moving to the save.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Result in Postman&lt;/strong&gt;&lt;br&gt;
After a few "failed renders," I finally got that beautiful 201 Created status. The response now includes:&lt;br&gt;
&lt;code&gt;"reading_time": 1&lt;/code&gt;&lt;code&gt;"message": "Yarn successfully spun!"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backend engineering is as much about &lt;strong&gt;Environment Awareness&lt;/strong&gt; as it is about syntax. You have to know where your &lt;code&gt;this&lt;/code&gt; is pointing and who is holding the "Baton" in the middleware chain.&lt;/p&gt;

&lt;h1&gt;
  
  
  node #javascript #mongodb #webdev #tutorial
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Building Yarncom: Phase 1 - The Authentication Handshake &amp; The Port 5000 Ghost</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Wed, 11 Feb 2026 15:31:46 +0000</pubDate>
      <link>https://forem.com/dillibe/building-yarncom-phase-1-the-authentication-handshake-the-port-5000-ghost-bob</link>
      <guid>https://forem.com/dillibe/building-yarncom-phase-1-the-authentication-handshake-the-port-5000-ghost-bob</guid>
      <description>&lt;p&gt;Every developer remembers their first "real" project. For me, &lt;strong&gt;Yarncom&lt;/strong&gt; is one of my first real projects. Instead of following a guided tutorial, I’m documenting a Progressive Journey of building a blogging API from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Stack&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Engine&lt;/strong&gt;: Node.js / Express&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: MongoDB Atlas&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: Bcryptjs &amp;amp; JWT&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Security Guard (Bcrypt &amp;amp; JWT)&lt;/strong&gt;&lt;br&gt;
I don't want to just save data; I want to secure it. I implemented a pre-save hook logic where passwords are scrambled using Bcrypt before they ever hit the database. For session management, I chose JWT. It’s like a digital keycard—you log in, you get a 1-hour pass, and you’re in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Port 5000 Mystery&lt;/strong&gt;&lt;br&gt;
If you're developing on a modern Mac, &lt;strong&gt;stay away from Port 5000&lt;/strong&gt;. I ran into a wall where my server said "Running", but Postman said " 404 ".&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Culprit&lt;/strong&gt;: AirPlay Receiver.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix&lt;/strong&gt;: &lt;code&gt;const PORT = process.env.PORT || 3000;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What’s Next?&lt;br&gt;
Phase 2 involves the Blog Model and a custom Reading Time algorithm. Stay tuned as I weave this community together!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>From Medical Doctor to Backend Engineer: Why I’m building my own E-commerce engine 🩺💻</title>
      <dc:creator>Dillibe Chisom Okorie</dc:creator>
      <pubDate>Tue, 10 Feb 2026 14:26:28 +0000</pubDate>
      <link>https://forem.com/dillibe/from-medical-doctor-to-backend-engineer-why-im-building-my-own-e-commerce-engine-559k</link>
      <guid>https://forem.com/dillibe/from-medical-doctor-to-backend-engineer-why-im-building-my-own-e-commerce-engine-559k</guid>
      <description>&lt;p&gt;Last year, I was graduating from medical school. Today, my "patients" are lines of code and database clusters.&lt;/p&gt;

&lt;p&gt;I’m currently on a journey to transition into Backend Engineering &lt;br&gt;
while enrolled at AltSchool Africa. But instead of just building "To-&lt;br&gt;
Do" apps, I’ve decided to build something real: a full-scale online &lt;br&gt;
store for my gadget business, &lt;a href="https://www.instagram.com/impextech?utm_source=ig_web_button_share_sheet&amp;amp;igsh=ZDNlZDc0MzIxNw==" rel="noopener noreferrer"&gt;impextech&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Problem&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Running a business like impextech involves a lot of moving parts—tracking inventory, managing sourcing, and handling customer orders. I realized that instead of using manual spreadsheets, I could build a custom solution that grows with me.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What I’ve Built This Week&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I just finished the first major pillar of the backend: &lt;strong&gt;Database Persistence&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  - Cloud Integration
&lt;/h3&gt;

&lt;p&gt;I moved my product data from local memory to a live MongoDB Atlas cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  - Data Modeling
&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;Mongoose&lt;/strong&gt;, I built a schema that handles everything from MacBook specs to automated timestamps.&lt;/p&gt;

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

&lt;p&gt;I implemented &lt;code&gt;dotenv&lt;/code&gt; to ensure my business credentials stay private.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The "Doctor" Perspective&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;People often ask why I’m switching lanes. To me, medicine and engineering are cousins. Both require deep diagnosis, an understanding of complex systems, and a commitment to solving problems.&lt;/p&gt;

&lt;p&gt;This store is just the beginning. My goal is to build a portfolio of software that solves real-world problems, and I’m documenting the entire process here.&lt;/p&gt;

&lt;p&gt;I’d love to connect with other career-switchers or backend devs! What was the first "real" project you built?&lt;/p&gt;

&lt;p&gt;#node #mongodb #showdev #backend #express #altschoolafrica #careerchange&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>database</category>
      <category>node</category>
    </item>
  </channel>
</rss>
