Scaffold Node.js APIs quickly using Tode-CLI

Hey, y’all! Hope you’re doing great! It’s been a while since I’ve posted an article. During this period I spent some time working on a node.js CLI for scaffolding APIs. In this article, I want to introduce you to the tool I created, Tode-CLI.

Why I created the tool?

First, I want to give a little insight into why I created the CLI I’m about to tell you about. I love using node.js (with express.js) to create APIs. It’s fast and simple to use.

However, I dislike having to create common things like models, controllers(routes), and service files from scratch each time I needed one. Additionally, I dislike the tedious efforts needed to set up authentication in applications that requires some level of authentication/authorization.

This led me to ask the question, “what can I do to avoid this repetition?”.  So, I decided to build a simple tool that could automate some of these things for myself.

After working on the tool, I decided to publish it to npm in case someone else might find it useful. Let’s take a closer look at the tool I created.

Introducing Tode-CLI

Tode-CLI is a tool for scaffolding node.js APIs. It provides commands to automate the boring stuff – creating models, services, controllers, registering routes. Thus, speeding up your development time.

Tode-CLI comes with an elegant ORM, objection.js, built on top of the famous query builder, knex.js. This makes interacting with databases a breeze when working with projects created by tode-cli.

The following will explore some features of the CLI.

Features

In this section, I’ll take a quick look at some of the core features of the CLI and give usage examples.

Generate/scaffold a project

The tode-cli provides a command to scaffold a project that has a straightforward folder structure. You scaffold a project by running $ npx tode-cli create-project hello-world.

This will generate a project, called hello-world, with the following folder structure:

Run npm i to install the node packages, then run npm run dev to serve your app locally. Your app will be served at http://localhost:8080/.

Hitting http://localhost:8080/ via a client (web browser, postman, etc) will give the following response:

The response above is showing all the none nested routes within the application. By default, a example route comes with the application.

Adding a Controller

In node applications, it is common to use route files to handle the routing in the app. However, in a tode-cli generated application we call these files controllers and they are stored in the controllers folder. Future updates may see a complete separation of controllers from routes, similar to what popular tools like Laravel and adonis.js does.

To add a controller to your app you simply run $ npx tode-cli add:controller <controller_name>. This will scaffold a controller(route) file like the following:

import { Request, Response, Router } from "express";

module.exports = () => {
  const router = Router();
  /**
   * Create a new Item
   */
  router.post("/", async (req, res) => {
    return res.send('demo/ - POST');
  });

  /**
   * Get all Items
   */
  router.get("/", (req: Request, res: Response) => {
    res.send("demo/  - GET");
  });

  /**
   * Get an Item by Id
   */
  router.get("/:id", (req: Request, res: Response) => {
    res.send("demo/  - GET /id");

  });

  /**
   * Update an Item
   */
  router.patch("/:id", (req: Request, res: Response) => {
    res.send("demo/  - PATCH /id");

  });

  return router;
};

Here we created a controller named demo. This controller is created with handlers for some basic HTTP request methods such as GET, POST, PATCH on the '/demo' path.

We can test that our controller is working by hitting http://localhost:8080/demo via a client(web browser, postman, etc). We should get the following response:

If we hit http://localhost:8080 again we will see the demo route in our list of routes. As you can see here, tode-cli apps offer a level of self-documentation for the routes within the application.

Models

Models are classes that represent a table in your database. You use methods on the model to perform queries on the table it represents via an easy-to-use ORM, Objection.js.

To create a model you run the command $ npx tode-cli add:model <model_name>. You’ll get a generated model like the following:

import BaseModel from "../BaseMode";

export class User  extends BaseModel {
  // Name of table that this model maps back to
  // Table name is the only required property.
  public static tableName = 'ENTER_TABLE_NAME';
  // Example property
  public foo!: string;

  // Add other table fields (columns) as properties to access them via the model

  // Define the relations to other models.
  // READ MORE at https://vincit.github.io/objection.js/guide/relations.html
  public static relationMappings = () => ({
    // specify relation with other modules
  })

}

In the above, I generated a model called User. Models on have one required property, tableName, which holds the name of the database table that the model represents. You can perform a query to fetch all users in your database table using await User.query(). Read more about objection.js’ queries here.

The static method relationMappings is where you define your model’s relationship with other models – basically representing your database relationships. Read more about objection.js’ relationships here.

Note: To use your models to perform queries you’ll first need to set up a database connection to the database with your tables. Read more here.

Services

Service files contain your business logic. To create a service you run the command $ npx tode add:service <service_name>. When you create a service, a file will be generated like the following.

import { ServiceReponse } from "../../config/constants";

class UserService {
  private _foo = "foo";

  constructor() {
    //
  }

  get foo() {
    return this._foo;
  }

  set foo(val: string) {
    this._foo = val;
  }

  public foobar() {
    //
  }
}

const UserService = new UserService();

export { UserService };

The above is the generated file for a service called UserService. You can then add methods to perform any logic inside this file. You’ll then call these methods from within a controller or another service. Services are also where you utilize your Models to perform database queries where necessary.

Authentication

Authentication is an essential part of most applications these days. With Tode-Cli you can integrate basic JSON Web Token (JWT) based authentication in your application by running a single command, $ npx tode-cli add:auth.

This command will create the following:

  1. Knex Migration to create a Users table in your database
  2. Login functionality which you can customise
  3. Registration functionality which you can customize
  4. Auth middleware which you can use on protected routes
  5. Login route – /auth/login
  6. Registration route – /auth/register

All you’ll need to do afterward is create the users table in your database by executing the migration file that was created. To do this, run the command $ npx knex migrate:latest. Now authentication is fully integrated.

Technologes used

Tode-CLI was developed with the following:

  1. TypeScript
  2. OCLIF – an open source framework for building command line interfaces (CLI) in Node.js.

We’ve covered some of the core features of Tode-CLI. I first created this tool for my personal use. I hope someone else finds it useful.

You can have a deeper dive into the docs and configurations here. Feel free to try it out. Don’t hesitate to report any issues you come across. I aim to improve the CLI as time goes by.

Thanks for reading, and until next time! Think, Learn, Create, Repeat!

About the Author

Leave a Reply

Your email address will not be published.

You may also like these