How I structure my Node.js REST APIs

Lars Wächter
The Startup
Published in
5 min readJan 9, 2020

--

When I started using Node.js for building REST APIs on the server side, I struggled a lot with the same question over and over again:

How should the folder structure look like?

Obviously there’s not a perfect or 100% correct answer to this question but after reading some articles regarding this topic, I found a folder structure that fits my needs pretty well. So today I’d like to show you how I structure my REST APIs.

I also published a GitHub repository including an example application which you can use as template for your own project.

The APIs are mostly component based what makes it much easier to request only the data we really need. For example we have a User component that contains all information about users.

One thing to mention is that I use express.js as web framework and TypeORM as ORM. Let’s have a look at the structure.

Directory: root

expressjs-api
└───db

└───dist

└───logs

└───node_modules

└───src

│ README.md
│ ...

This structure is nothing special and shouldn’t be new to you. It’s actually a basic Node.js setup. The interesting part is the src folder on which our focus lies.

So what do we have in here?

expressjs-api
└───src

└───api
│ │
│ └───components
│ │
│ └───middleware
│ │
│ │ routes.ts
│ │ server.ts

└───config

└───services

└───test
|
│ app.ts

From here on, we’ll always work from the top of the directory down and I explain each one. Let’s start with the api directory.

Directory: src/api/components

expressjs-api
└───src

└───api

└───components

└───article

└───auth

└───country

└───user
│ helper.ts
│ index.ts

Here we have the heart of our component based Node API. Each component has its own routes, controller, model, repository, policies, tests and templates.

Let’s have a look at the User component.

Directory: src/api/components/user

expressjs-api
└───src

└───api

└───components

└───user

└───services
| │ mail.ts
└───templates
| │ confirmation.html
| | invitation.html
│ controller.ts
│ model.ts
│ policy.json
│ repository.ts
│ routes.ts
│ user.spec.ts

As you can see a single component includes the files I mentioned before. Most files represent a class that is exported. Of course, you can add here more component specific stuff like config or test files.

Since I have multiple components and their classes have the same structure most of the time, I also create interfaces that are implemented in the classes, especially within the service class. This helps me to keep the components’ structure straight.

Moreover, we have the services directory here which includes local component services like mail for example. Those interhite from the global services.

The templates directory includes mail HTML templates for the given component. For dynamically rendering HTML code I highly recommend ejs.

controller.ts

The controller class handles incoming requests and sends the response data back to the client. It uses the repository class to interact with the database. Request validation happens via middleware few steps before

model.ts

The model represents the database model for its component. In my case it’s a TypeORM class. Mostly it’s used by the repository classes.

policy.json

The access policy for the component, where we manage the access rights for operations like reading / updating / deleting etc. data records based on the user role.

{
"Admin": [{"resources": "user", "permissions": "*"}],
"User": [{"resources": "user", "permissions": ["read"]}]
}

repository.ts

The repository class acts like a wrapper for the database. Here we read and write data to the database. Furthermore, we can implement caching for example.

You can import the repository class into any other file and query the data for this component from the database. Moreover, it prevents us from writing redundant code since we don’t have to rewrite the SQL statements multiple times.

Since most component repositories need the same basic access methods like readAll, read, save and delete I use a generic parent class that includes all these methods. This saves a lot of code.

See AbsRepository for the implementation.

routes.ts

Here we define the API endpoints for the corresponding component and assign the controller methods to them. Moreover we can add more stuff like

  • authorization (e.g. JWT)
  • permission checking (ACL)
  • request body validation
  • component specific middleware in here.

user.spec.ts

This is the test file for testing the component and its endpoints. You can read more about testing this architecture here.

Directory: src/api/middleware/

nodejs-api-structure
└───src

└───api

└───middleware
│ auth.ts
│ compression.ts

This folder includes all the API’s global middlewares like authentication, compression, request logging etc.

File: src/api/routes.ts

nodejs-api-structure
└───src

└───api
│ routes.ts

Here we register all component and middleware routes.

File: src/api/server.ts

nodejs-api-structure
└───src

└───api
│ server.ts

Here we declare everything required for our express server:

  • import middlware / component routes
  • error handling

Later on, we can import the server class for unit tests as well.

Directory: src/config

nodejs-api-structure
└───src

└───config
│ globals.ts
│ logger.ts
│ permissions.ts

This directory includes configuration files. This could be for example:

  • global variables
  • logger config
  • ACL permission
  • SMTP config

Directory: src/services/

This directory contains global services we need for sending mails, authorization or helper methods for example.

expressjs-api
└───src

└───services
│ auth.ts
│ helper.ts
│ mail.ts
| redis.ts

auth.ts

Here we setup things like our passport strategies and define authorization methods.

helper.ts

The helper class contains helper methods for hashing, UUIDs and so on.

mail.ts

This service is used for sending mails and rendering their templates.

File: src/test/

This directory includes a test factory for running the component tests. You can read more about it here.

File: src/app.ts

This is the startup file of our application. It initializes the database connection and starts the express server.

nodejs-api-structure
└───src
│ app.ts

All together

Last but not least a complete overview of the project structure:

expressjs-api
└───src

└───config
│ │ globals.ts
│ │ logger.ts
│ │ permissions.ts

└───api
│ │
│ └───components
│ │ │
│ │ └───article
│ │ │
│ │ └───user
| │ │ │
| │ │ └───templates
| │ │ | │ confirmation.html
| │ │ | │ invitation.html
│ │ | │ controller.ts
│ │ | │ model.ts
│ │ | │ policy.json
│ │ | │ repository.ts
│ │ | │ routes.ts
│ │ | │ user.spec.ts
│ │
│ └───middleware
│ │ │ compression.ts
│ │ │ logging.ts
│ │
│ │ routes.ts
│ │ server.ts

└───services

└───test
|
│ app.ts

That’s it! I hope this is a little help for people who struggled with the same question and didn’t know where or how to start. I think there are still many things you can do better or in a more efficient way.

If you’re interested in writing unit tests for Node.js REST APIs have a look at this article which covers the same architecture.

--

--