Building a professional API with NodeJS, Typescript, ExpressJS, MongoDB, Jest + Deploy to Heroku — PART 2

Guide:
Part 1: Starting the project and set up a minimal NodeJS REST API
Part 2 (you are here): Organizing the project, adding routes, controllers and isolated server
Part 3: Add typescript support + refactoring all javascript code to typescript and ES6
Part 4: Learn CRUD paradigm and implements it in NodeJS and test with CURL
What you will learn?
In this article, you’ll learn how to structure the project folder and files. Set up express routes, controllers and separate the application from server.
Add .gitignore file
Let’s add a .gitignore in root folder of project to avoid send node_modules folder to git. Create a .gitignore file with this line:
node_modules
Folders and files structure
Create the main folders of our API aplication. Create these folders inside of src folder.
- controllers
- routes
Add these files in inside src folder:
- router.js
- server.js
Set up app/server scope
Let’s separate the server from the application. This allows us to have a decoupled structure and will be useful for next steps to structure automated tests, temporary databases and other advantages.
In part 2 of this tutorial our server ran on app.js. Now let’s actually run it on server.js and app.js will only have application settings.
Now, your app.js should seems like this:
const express = require('express')// import our local router file
const routes = require('./routes')// init express app
const app = express()// allow express to work with json
app.use(express.json())// router
app.use(routes)// export app to import into server.js
module.exports = app
Note that we no longer have the routes and app.listen in this file.
Set up server.js
The server now has the role of just initializing the application. Your server.js file should seems like this:
const app = require('./app')const PORT = 3000app.listen(PORT, () => console.log("Server is running at PORT 3000 🚀"))
Now, set up the routes. Inside routes folder, create a global.js file, and define some basic route.
const express = require('express')
const router = express.Router()// your routes paths and methods
router.get('/api', (req, res) => { res.send('API online') })module.exports = router
Now let’s import this routes file into our routes.js
const express = require('express')
const router = express.Router()// your routes paths and methods// single basic route at the base path of your application
router.get('/', (req, res) => { res.send('API online') })module.exports = router
From now on, you must start your server with the command node src/server.js instead of src/app.js. Run your server and access the route http://localhost:3000 using your browser.
—
Note that we got the same result as part 1 of the article. But now in a structured and organized way. Let’s go deeper. Now, instead of passing the return function directly in the route, let’s leave that to the controllers. And each route calls your controller.
Inside controllers folder, create the file global.js. In this file, lets create a controller function:
const globalControllers = {
healthyCheck(req, res) { res.send('<h2>API is running</h2>') }
}module.exports = globalControllers
Now, we need to import this controller into your route. So, in routes/global.js, lets import the controller and use it instead the function:
const express = require('express')const router = express.Router()const globalController = require('./controllers/global')
// your routes paths and methods// single basic route at the base path of your application
router.get('/', globalController.healthyCheck) // we've changed thismodule.exports = router
And now, you can restart your API and open, in your browser, the route http://localhost:3000 and you should get the message “API Online”.
Great! In this post we saw how to better structure our files, use the express route system, controllers and work with imports/exports in javascript.
In the next steps, we’ll add typescript support and refact code to ES6+ using import/export syntax. Connect to MongoDB, put in JWT authentication, error handling, and a lot of more things, so stay tuned!