How To Build a Node.js Express App in Under 5 Minutes?
Tags: programming, node, webdev, javascript
Published: 2023-12-04 18:07:22

As we move into 2024, the ideology behind faster development times has never been more critical. But, when building a Node.js Express app, that hasn't always been the case. In my experience, it usually takes a long time to bootstrap an Express API. This includes:

1.  Creating a boilerplate NPM project using `npm init`.
2.  Installing the required libraries - Express, Nodemon, Body Parser, and TypeScript to configure your Express Server
3.  Setting up ESLint and creating the perfect ruleset for the project
4.  Setting up Module Federation - If you want to share code between your Node.js and Express.js microservices.

This means you're spending more time on things that aren't adding value to your software. You'd be better off building a feature, but instead, you're configuring a linter or a build command.

# How Can We Build Faster Express Apps?

> The short answer is to treat your service as a component

It would help if you had a toolkit that lets you build your Express.js API as components where each component is designed, built, tested, and versioned in its isolated environment **without you doing any configuration.** Doing so allows you to start by building features without focusing on any operational needs.

To do this, you'd need to break your app down into two areas:

1.  The actual app
2.  The services

Your app and service could be treated as two components, where your service component holds the feature, while the app component provides a runtime to execute your service. By creating an independence of this nature, you can improve your development cycle time by testing your services without spinning up the app.

> And one such tool that I've found that supports this component-driven approach is [Bit](https://bit.dev).

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/kFCAcsWVdl.png)

**Figure: Bit.dev**

Bit is a next-generation build system for developing composable software. It let's you build your components in an isolated environment and uses services like Ripple CI to propagate changes up your component tree. For example, consider the diagram depicted below:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/-dS9KGIVoX.png)

**Figure: A sample component-driven API**

Let's say that everything we've defined above is a component. And let's say that you change the logic on `GetBlogById` to return an error if Blog is not found.

If you make this change, it should automatically reflect the change in your `BlogBackend` route, right?

Well, this is what Bit does. It keeps track of the dependencies that your component uses, and if it detects a change, it propagates it up the tree, creating a Ripple effect, thus deploying the entire tree again to ensure that you're running on the latest change.

> Sounds interesting. This is how I build my apps daily, and I thought I'd share my experience with it.

# Building an Express.js App with Bit

## Step 01: Pre-requisites

To build an Express.js app in under 5 minutes, you’ll need to install the [Bit CLI](https://bit.dev/docs/getting-started/installing-bit/installing-bit/) using the command:

```nginxconf
npx @teambit/bvm install

```

Next, you’ll need to verify that the CLI has been installed successfully by running the command:

```postgres
bit --version

```

If you’ve installed Bit correctly, you should see the screenshot below.

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/DfO1h_0Ca4.png)

**Figure: Installing Bit Correctly**

Next, you'll need to create an account on [Bit Cloud](https://bit.cloud/). After you've created your account, go ahead and [create a scope](https://bit.cloud/create-scope) with the name **blog:**

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/nLmAZUed0m.png)

**Figure: Creating a scope on Bit Cloud**

> A Scope is a remote server in which your components live. Think of it like a GitHub repository, but it's not language-oriented. You can store anything in a scope and let people contribute to it.

{% embed https://bit.dev/reference/reference/scope/scope-overview/ %}

## Step 02: Creating the Express.js App

Next, in a new directory, initialize a Bit workspace using the command:

```ino
bit init

```

By doing so, you'll create a space for local development. You'll see a file - `workspace.jsonc`. Open that file and update the `defaultScope` parameter with the following - `<<YOUR-USERNAME>>.<<SCOPE-NAME>>`. After you do so, it should look like the snippet I've attached below:

```
"defaultScope": "dummyorg.blog",

```

> Replace this with your username, and scope we created in Step 01.

Notice that your workspace isn't tied to a programming runtime. So, you can create an Express API and immediately create a React/ Angular/ React Native/ Vue.js component to consume the API as well.

Next, let's create an Express App. This can be done in one command:

```
bit create express-app blog-api && bit install --add-missing-deps

```

If you've done this correctly, you'll see the output:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/xsyWTSY6f3.png)

**Figure: Creating the Express.js app**

Next, you'll see a directory as below:

**![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/SkwYQpwtSC.png)Figure: Exploring the project directory**

Go ahead and open up your app root - `blog-api.app-root.ts`. You'll see the following code:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/28ziquqC4P.png)

**Figure: The code generated in the app root**

The code above is enough to launch your app as a bare Express server. It initializes an app, registers routers, and then listens to a port that's resolved in the `getPort` function. To start this Express App, let's run the following commands:

```mips
bit use blog-api && bit run blog-api

```

After you've done so, your Express.js app should spin up:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/cVuS3yq6BM.png)

**Figure: Spinning up the Express App**

Next, you can open the sample endpoint - `localhost:3000/`. This should launch your Express app and show the output:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/x1J2FHQM1q.png)


**Figure: The sample app**

Okay, but, this doesn't truly speak about component-driven development. To see this in action, run `bit start`. You should see a development server spin up:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/DeYbGcJNCP.png)

**Figure: Viewing the Workspace**

You can click on the `blog-api` and view it as its component:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/ihb3zOpV1K.png)

**Figure: Viewing the Express App component**

## Step 03: Adding Routes to the API

Next, let's add routes to our API. Let's do this by creating two new components:

1.  GetBlogs
2.  GetBlogById

But first, it's important to note that both of our Routes will use the same Entity - "Blog", and will have a single data source. So, let's first set up a Blog entity and a mock data set.

To do so, let's create the entity component first using the command:

```crm
bit create node entities/blog

```

You should see the output shown below:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/xMRmMS7HaU.png)

**Figure: Creating the Blog Entity Component**

Next, let's define the entity component by adding the following code to the `blog.ts` file:

```ts
/**
 * An entity class that represents a Blog
 */
export class Blog {
  /**
   * the id of the blog post
   */
  private _id: string

  /**
   * the title of the blog
   */
  private _title: string

  /**
   * the plot of the blog (summarized version of the content)
   */
  private _plot: string

  /**
   * the day the blog was published - in milliseconds
   */
  private _publishedDate: number

  constructor(id: string, title: string, plot: string, publishedDate: number) {
    this._id = id;
    this._title = title;
    this._plot = plot;
    this._publishedDate = publishedDate;
  }

  getId() {
    return this._id;
  }

  getTitle() {
    return this._title;
  }

  getPlot() {
    return this._plot;
  }

  getPublishedDate() {
    return this._publishedDate;
  }
}

```

Now that we have an entity component, we can share this across all other components we create. This includes the sample data along with the other API Route components.

So, next, let's create the Sample Data component using the command:

```crm
bit create node mocks/sample-data

```

Next, open the file `sample-data.ts` and include the code:

```postgres
import { Blog } from '@dummyorg/blog.entities.blog';

const data: Blog[] = [
  new Blog("001", "Sample Title 01", "Sample Plot 01", Date.now()),
  new Blog("002", "Sample Title 02", "Sample Plot 02", Date.now()),
  new Blog("003", "Sample Title 03", "Sample Plot 03", Date.now()),
  new Blog("004", "Sample Title 04", "Sample Plot 04", Date.now()),
  new Blog("005", "Sample Title 05", "Sample Plot 05", Date.now()),
]

export function sampleData(): Blog[] {
  return data;
}

```

As you can see, we're using the entity component that we created before.

> The cool thing about this is that it will automatically check and update all of its usage whenever we change the entity component.

So, if we introduce a new field in the constructor for the Blog, the `sample-data` will fail its build in the Ripple CI as the component cannot handle the new change introduced into the Blog entity.

Next, if we head back to the development server and open the `sample-data` component, you should be able to see the component in action:

![image](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/jRbP1U5mZD.png)

**Figure: The Sample Data Component**

Next, let's set up the two routes using the command:

```
bit create node routes/get-blogs routes/get-blog-by-id

```

This will create two Node components that will act as the two routes in our Express.js API:

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/GX4oomq4mH.png)

**Figure: Creating the Components**

Next, you can define the implementations in the components as shown below:

```js
// get-blogs.ts

import { Request, Response } from 'express';
import { sampleData } from "@dummyorg/blog.mocks.sample-data";

const blogs = sampleData();

export function getBlogs() {
  return blogs;
}

export function getBlogsRoute() {
  return {
    method: 'get',
    route: '/blogs',
    middlewares: [
      async (req: Request, res: Response) => {
        const results = await getBlogs();
        return res.json(results);
      },
    ],
  };
}



// get-blog-by-id.ts

import { Request, Response } from 'express';
import { sampleData } from "@dummyorg/blog.mocks.sample-data";

const blogs = sampleData();

export function getBlogById(id: string) {
  const blogById = blogs.find((blog) => blog.getId() === id);
  if (!blogById) {
    throw new Error('Blog not found')
  }
  return blogById;
}

export function getBlogByIdRoute() {
  return {
    method: 'get',
    route: '/blogs/:id',
    middlewares: [
      async (req: Request, res: Response) => {
        const { params } = req
        const results = await getBlogById(params.id);
        return res.json(results);
      },
    ],
  };
}



```

As you can see, we've not only implemented the business logic, but we've also exported two new "route" functions. These route functions create a middleware for each route and execute the business logic. We will leverage these middleware route functions in our API server to hook the routes to the app.

Next, head over to your development server to view the two components:

![image](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/lWnDQfpCcT.png) **Figure: Get Blogs Component**

![image](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/ksJ41dNXhp.png) **Figure: Get Blog By ID Component**

## Step 04: Integrating the Routes to the API

Now that we've built our API routes let's hook the routes to the API. To do so, head back to your API Component and open the `api-root` file, and update the `registerRoutes` function with the code shown below:

```js
import { getBlogByIdRoute } from '@dummyorg/blog.routes.get-blog-by-id';
import { getBlogsRoute } from '@dummyorg/blog.routes.get-blogs';

function registerRoutes(app: Application.Application) {
  const mockRoute = getMockRoute();
  // introduce new routes
  const routes = [mockRoute, getBlogByIdRoute(), getBlogsRoute()];
  routes.forEach(route => {
    app[route.method](route.route, route.middlewares);
  })
}

```

Next, all you have to do is launch the app by running the command:

```ino
bit run blog-api

```

Next, hit each endpoint to see the response:

*   Route - localhost:3000/blogs

![image](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/ZbyJ9ky3Ug.png)

*   Route - localhost:3000/blogs/001

![image](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/GkXFLy9seY.png)

And, there we have it! Our API is up and running, and it didn't even take 5 minutes!

## Step 05: Sharing the API

Next, let's share the API for everyone to view and contribute using the command:

```ino
bit tag && bit export

```

This will automatically ship the components to the scope we created earlier and will kick off a Ripple Build.

![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/HocFGoqZfL.png)Figure: [The Ripple Build](https://bit.cloud/ripple-ci/job/dummyorg-main-bump-dependencies-versions-Q4Mrcks8o)

As you can see, Ripple CI knows the entire component tree and how each component is used.

## Step 06: Automated Builds with Ripple CI

Ripple CI not only builds your components but also tracks differences in the tree in which your component is being used and builds the tree to support the changes.

For example, let's update the `get-blogs.ts` route to return the following:

```js
export function getBlogsRoute() {
  return {
    method: 'get',
    route: '/blogs',
    middlewares: [
      async (req: Request, res: Response) => {
        const results = await getBlogs();
        return res.json({ results }); // Return JSON now.
      },
    ],
  };
}

```

We've update the `res.json` line to return a JSON object of `results`. Let's sync this change to the cloud using the command:

```ino
bit tag && bit export

```

Next, head over to Ripple CI to see the build:

# ![](https://www.writergate.com/uploads/dc64a919-1200-42d3-90c6-9bc96dd9f4fa/UH49qviFYn.png)

**Figure:** [**Ripple Build for Diff**](https://bit.cloud/dummyorg/blog/~ripple-ci/job/dummyorg-main-bump-dependencies-versions-iPMYiMVPE)

As you can see, Ripple identified that `get-blogs` had changed, and as a result, it built the application as well. This ensures that our app is always up to date.

Furthermore, you can extend the deployment to ship your app off to servers for hosting automatically!

# Wrapping up

Well, that was interesting. It's not every day that we build Express apps in under 5 minutes!

If you like what you see, check out the full implementation, which includes unit-testing and component composition development - [all in my Bit Cloud Scope.](https://bit.cloud/dummyorg/blog)

I hope you found this article helpful.

Thank you for reading.

# Learn More

{% embed https://blog.bitsrc.io/update-multiple-npm-packages-a1d49636ffca?source=collection_home---4------1----------------------- %}