38
Scaffold Node.js APIs quickly with Todo-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.
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
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.
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:
Users
table in your database/auth/login
/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:
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!
38