An Introduction of NestJS, a Node.js web/app server framework.
This post aims to explain basic concepts in back-end programming. Although NestJS is a Node.js (JavaScript) tech-stack, you will have a thorough understanding of many concepts of designing back-end/API programming (not specifically for Node.js) after reading this post.
Note that this post can be used as a complement of the official tutorial of Nest.js. I believe that official documents are best fit to learn a tech, so I recommend to take a step-by-step hands-on tutorial first from the following link.
This post aims to explain basic concepts in back-end programming. Although NestJS is a Node.js (JavaScript) tech-stack, you will have a thorough understanding of many concepts of designing back-end/API programming (not specifically for Node.js) after reading this post.
Overall View
Before We Start: Boilerplate Code
Create a NestJS project using the Nest CLI tool, choose any package manager you like (I prefer yarn
):
nest new hello-nest
In order to support Intellij IDEA/WebStorm, we need to apply the following configurations after opening the created project. In JetBrains IDE:
- Click on the dropdown menu next to the Run/Debug configurations in the top-right corner of the IDE.
- Select "Edit Configurations" or "Add Configuration" option. This will open the Run/Debug Configurations dialog.
- Click the "+" button in the top-left corner of the dialog to add a new configuration.
- Choose "Node.js" from the list of configurations.
- In the "Name" field, provide a meaningful name for your configuration (e.g., "Nest.js").
- In the "JavaScript file" field, enter the path to the Nest CLI file, typically
node_modules/.bin/nest
, or use the full path to thenest
executable. - In the "Application parameters" field, enter the Nest.js CLI command you want to use, such as
start
for running your application. - Set the "Working directory" to the root folder (which will automatically generated by the IDE) of your Nest.js project.
FYI, you can follow the detailed Node.js configuration tutorial provided by JetBrains in the following link.
Well done, you have configured the Run/Debug button. You can now simply click Run button to run the server.
The default port number of NestJS created by CLI is 3000
. After you run the server, you can use your web browser to navigate to http://localhost:3000 and you can see the "Hello World!" message, which means a successfully run of NestJS.
Controllers
Controllers are the codes to receive requests and send responses. It works like a bank teller. Here is a piece of code of controller:
Mention that you should not write any implementation in controller layers (although you are allowed) since service layers are designed for code reuse.
Controllers should handle HTTP requests and delegate more complex tasks to services, which are plain TypeScript classes that are declared as providers
in a module (building block that helps organize and structure the code of your application) as following code.
Services
NestJS utilizes the concept of "providers" for creating and managing services. In NestJS, a provider is a class annotated with the @Injectable()
decorator
You may like to alternate the generated code inside app.service.ts
to play with implementation of business logics.
By visiting localhost:3000, you get Hello World! And the current time is 12:06:50 PM
.
You should implement any business logics inside Services. As the following code given, the getCurrentTime()
method get a current local time. It is declared with private means the method can only be called inside app.service.ts
.
Method Scoping (annotated with private, public, ...) is important since it provides functions of encapsulation, security. It also create a maintainable code.
Here is why it provides a maintainable code: Image that you are at a bank. You have a business account and an individual account. You go to the business counter: /business/deposit
and you sign a form (request JSON)
The counter teller knows that you want to deposit 1000 USD to account 99887766, and you also provide a legal signature (authentication), which means you are actually you (although it can be forfeit by some approaches such as 51% attack).
The service code inside business.service.ts
may be look like:
The private scope states that transaction()
can be only used in business.service.ts
, which means it handles only business services. When we implement individual.service.ts
, there can also be a private transaction()
method for individual services, which creates a maintainability. (otherwise we may write code transaction_business()
and transaction_individual()
)
Routing Mechanism and RESTful convention
Controllers need routing mechanism (there are different bank services, individual, business, ...). Routing is implemented by concating of URL. A RESTful design (convention) of URL is like:
/account/create
/account/{id}/delete
/account/{id}/update
/account/{id}
/item/{id}
/items
/item/page/10
Where {id}
is user id for any individual users, such as 1145141919810
. The URLs in the previous code blocks represents create a user, delete a user according to his/hers id, such as /account/1145141919810/delete
, update a user according to id, and read user information (such as email) according to a id. Generally speaking, what server's job, commonly, are Create, Read, Update and Delete (CRUD).
/items/{id}
demostrates routing. The manipulation within the Controller that listening on the URL starts with item
is item-related. Image an online shopping website, if we want to get information of a specific item by its item id.
/items
, as you guess, this URL is for retrieving all items (products) as a huge list.
Similarly, follow the RESTful convention, /item/page/10
retrieving a specific page (the 10th page) of a collection of items. It works for pagination of a list of products in an online shopping website, since using one page to display all products is slow.
Note: in a modern front-end back-end separation design of web applications. These URLs returns a JSON rather than a rendered web page. Front-end back-end separation design is much similar to the pattern of Mobile/Embedded Application design.