Is an API and Router two separate things?

I have a Node.js with Express.js app. I have folders like such:

src
   /models
   /router
   /store
   /api/v1
  index.js

My router folder has a file called index.router.js which contains my app’s routes e.g:

import UserAPI from '../api/v1/user.api.js'
expressRouter.post('/register', function async function (req, res)  {

         await UserAPI.registerUser({
         EMail: req.body.EMail,
         Password: req.body.Password,
         Name: req.body.Name
});

The above is a route to an API so it went into my index.router.js file. To perform an API action on this endpoint, I created another file for API functionality called user.api.js and it would contain something like:

async function registerUser({EMail, Password, Name}) {
  // Import method from model file and perform DB action
});

As the application has grown I have come to wonder whether I have made it too complex and created an unecessary layer with a separate file of user.api.js which could possibly be refactored to be part of index.router.js.

What I do not understand is what is the standard practice of file structuring an API for scalability and should the API endpoints be in a separate file/folder of api/v1, api/v2 or should they be part of the router?

One thing that could be advantagous of having separate api files is resuability. Because it only contains functions and no routing, the functions could be reused across many different router files.

Answer

You have basically re-invented the MVC design pattern.

It’s not overly complicated. It is considered good practice and encouraged.

C

Traditionally, what you call Routers is usually called the Controller. The job of the controller is simply to handle routing, handle argument parsing (request body, query parameters, is user logged in etc.) and sometimes handle validation. This is exactly what Express is designed to do. And Express allows controller functionality like authentication and validation to be refactored into middlewares.

Note: Sometimes you will see tutorials on the internet where people separate controllers and routes. My personal recommendation is do not do this. Express routing has been designed to be perfect for writing controllers. About the ONLY reason to separate them is if you have two different URLs that do the exact same thing. In my opinion that is better handled by a redirect.

M

Traditionally what you call API is called the Model. The model is your traditional collection of objects or data structures that you learned to program with. The model is what performs the application logic. Normally classes or modules that implement models are not labeled with anything. For example a user model would not be called UserAPI or UserModel but simply called User. However, what you name things is just a convention. Stick with what makes sense to you.

V

The final part of MVC is the View. In Express the view is simply res.json() or res.render() with its associated HTML template. This part is 99% already written by Express developers – you just need to tell the view functions what to send to the front-end.

Your architecture is good

There are very good reasons for separating the model (API) from the controller (router). First is that it allows you to solve your problems without polluting your core logic with parameter parsing logic. Your models should not need to worry about weather the user is logged in or how data is passed to it.

Second is that it allows you to use your model (API) logic outside of Express. The most obvious use for this is unit testing. This allows you to unit test your core logic without the web parts of the code. I also usually write utility scripts that I can use to do things like create a new user, dump user data, generate authentication token so I can use it with Postman etc.

For example you can create a script like:

#! /usr/bin/env node
// register-user.js

import UserAPI from '../api/v1/user.api.js'

UserAPI.registerUser({
    EMail: process.argv[2],
    Password: process.argv[4],
    Name: process.argv[3]
})
.then(x => {console.log(x); process.exit()})
.catch(console.error);

Which you can then execute on the command line to create new users without needing to run the server:

$ ./register-user.js [email protected] 'My Name' 123456

It looks like your software is already structured according to MVC. Keep it that way. It will make maintaining and modifying the software a little easier.