DEV Community

ShyGyver
ShyGyver

Posted on • Edited on

NodeJS Rest API with @novice1/app

Yet another Node.js library based on Express. What could make you want to use @novice1/app?
I'm glad you asked.

@novice1/app is as fast and minimalist as Express with new functionalities and its own plugins that give a purpose to its existence.

Through this article and those to come, I'm going to show how it can be used to build small/mid-size Rest APIs, validate data, integrate websockets into your server, generate documentation for Swagger UI and/or Postman, etc ...

Setup

First we initialize a project by running the command in the terminal

npm init
Enter fullscreen mode Exit fullscreen mode

and install the dependencies

npm install --save-dev @types/cookie-parser @types/cors @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser dotenv eslint ts-node typescript
npm install @novice1/app @novice1/logger @novice1/routing cookie-parser cors express nodemon tslib
Enter fullscreen mode Exit fullscreen mode

Once done, we can add the following scripts in the file package.json that was created with npm init:

{
    "scripts": {
        "build": "tsc",
        "dev": "nodemon",
        "lint": "eslint src/**/*.ts",
        "start": "node lib/index.js"
    }
}
Enter fullscreen mode Exit fullscreen mode

To use those scripts we have to configure eslint, nodemon and typescript. Here is what I recommend as configuration files at the root of the project (feel free to add more options):

.eslintrc.json

{
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint"
    ],
    "rules": {
        "quotes": [1, "single"],
        "quote-props": [1, "as-needed"]
    }
}
Enter fullscreen mode Exit fullscreen mode

nodemon.json

{
    "watch": [
        "src"
    ],
    "ext": "ts,json",
    "ignore": [
        "src/**/*.spec.ts"
    ],
    "exec": "ts-node -r dotenv/config ./src/index.ts"
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.json

{
    // see https://www.typescriptlang.org/tsconfig
    "include": ["src"],
    "exclude": ["node_modules"],
    "compilerOptions": {
      "typeRoots": ["node_modules/@types"],
      "module": "CommonJS",
      "lib": ["DOM", "ES6"],
      "target": "ES6",
      "importHelpers": true,
      "declaration": true,
      "sourceMap": true,
      "outDir": "./lib",
      "rootDir": "./src",
      "strict": true,
      "noImplicitReturns": true,
      "noFallthroughCasesInSwitch": true,
      "noUnusedLocals": true,
      "noUnusedParameters": true,
      "moduleResolution": "node",
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true
    }
  }

Enter fullscreen mode Exit fullscreen mode

Now that we are done with the "basic" setup, we can start programming the application.

First application

Let's program our services, routes and http server.

Services

To help the development process, we need a debugging utility.

src/services/debug.ts

import logger from '@novice1/logger';

logger.Debug.enable([
    'route*'
].join('|'));

export const debugRoute = logger.debugger('route');
Enter fullscreen mode Exit fullscreen mode

There, we enable all namespaces starting with 'route' (route*) and create the debugger debugRoute in namespace 'route'. That way, we know that everything that debugRoute will log will be displayed.

Routes

Our first route, for testing purposes, will simply render "Hello World!" or "Hello <name>!", <name> being the value of the url variable name.

src/routes/hello-world.ts

import routing from '@novice1/routing';
import { debugRoute } from '../services/debug';

// hello-world
export default routing().get({
    path: '/hello-world'
}, (req, res) => {
    debugRoute.extend('hello-world').debug(req.path);
    res.json(`Hello ${req.query.name || 'World'}!`);
})
Enter fullscreen mode Exit fullscreen mode

Our second route is optional. It will enable pre-flight request for all requests.

src/routes/cors-options.ts

import cors from 'cors';
import routing from '@novice1/routing';

// enable CORS (Cross-origin resource sharing) pre-flight request
export default routing().options({
    path: '*'
}, cors())
Enter fullscreen mode Exit fullscreen mode

From that we simply allow cross-origin resource sharing pre-flight without restrictions.

Then we export all routers from one module.

src/routes/index.ts

import corsOptions from './cors-options';
import helloWorld from './hello-world';

// all routers
export default [
    corsOptions,
    helloWorld
]
Enter fullscreen mode Exit fullscreen mode

Server

We can now use @novice1/app to register middlewares and routes.

src/app.ts

import { FrameworkApp } from '@novice1/app';
import cookieParser from 'cookie-parser';
import express from 'express';
import cors from 'cors';
import routes from './routes';

// init app
export const app = new FrameworkApp({
    framework: {
        // middlewares for all requests
        middlewares: [
            cookieParser(),
            express.json(),
            express.urlencoded({ extended: true }),
            cors()
        ]
    },
    routers: routes
})
Enter fullscreen mode Exit fullscreen mode

And run the server on a specific port:

src/index.ts

import logger from '@novice1/logger';
import { app } from './app';

const PORT = process.env.PORT ? parseInt(process.env.PORT) : 8000;

// start server
app.listen(PORT, () => {
    logger.info('Application running on port', PORT)
})
Enter fullscreen mode Exit fullscreen mode

Run the application

Development

To start the server in development mode, we add environment variables in the file .env.

.env

PORT=8080
Enter fullscreen mode Exit fullscreen mode

This will set the environment variable PORT to 8080 when using the dependency dotenv (see nodemon.json file).

Then we can start the server with the following command in the terminal:

npm run dev
Enter fullscreen mode Exit fullscreen mode

You should see something like that in your console:

[nodemon] starting `ts-node -r dotenv/config ./src/index.ts`
info : Application running on port 8080
Enter fullscreen mode Exit fullscreen mode

Open your favorite browser and go to http://localhost:8080/hello-world or http://localhost:8080/hello-world?name=stranger to see the result.

Production

In a production environment, you should check, build and start the server as:

npm run lint
npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

What now?

So we have a REST API but really nothing out of what Express can already do. In the next article, we will see how to use @novice1/validator-joi to validate request data and give a better structure to our project.

References

You can see the result of what we have done till now right here on Github.

Top comments (0)