使用FortJs使用现代JavaScript开发Node.js

介绍 (Introduction)

Nodejs gives you the power to write server side code using JavaScript. In fact, it is very easy and fast to create a web server using Nodejs. There are several frameworks available on Node package manager which makes the development even easier and faster.

Nodejs使您能够使用JavaScript编写服务器端代码。 实际上,使用Node.js创建Web服务器非常简单快捷。 Node软件包管理器上有几种可用的框架,这些框架使开发变得更加轻松和快捷。

But there are a few challenges in Nodejs development:

但是,Nodejs开发中存在一些挑战:

  • Nodejs is all about callbacks, and with more and more callbacks you end up with a situation called callback hell.

    Node.js完全是关于回调的,随着越来越多的回调,您最终会遇到称为回调地狱的情况。
  • Writing readable code.

    编写可读的代码。
  • Writing maintainable code.

    编写可维护的代码。
  • You don't get much intellisense support which makes development slow.

    您没有太多的智能感知支持,这会使开发变慢。

If you are quite experienced and have a good knowledge of Nodejs, you can use different techniques and try to minimize these challenges.

如果您有丰富的经验并且对Node.js有所了解,则可以使用不同的技术并尽量减少这些挑战。

The best way to solve these problems is by using modern JavaScript ES6, ES7 or TypeScript, whatever you feel comfortable with. I recommend TypeScript, because it provides intillisense support for every word of code which makes your development faster.

解决这些问题的最佳方法是使用现代JavaScript ES6,ES7或TypeScript,无论您喜欢什么。 我推荐TypeScript,因为它为每个代码字提供了intillisense支持,从而使您的开发更快。

So I created a framework called FortJs which is very easy to learn and use. FortJs enables you to write server-side code using ES6 or TypeScript which is modular, secure, and pretty much just beautiful and readable.

因此,我创建了一个名为FortJs的框架,该框架非常易于学习和使用。 FortJs使您可以使用ES6或TypeScript编写服务器端代码,该代码模块化,安全且几乎美观且可读。

特征 (Features)

Some of the important features of FortJs are:  

FortJ的一些重要功能包括:

  • Based on Fort architecture.

    基于Fort体系结构。

  • MVC Framework and follows OOPS approach so everything is class and object.

    MVC框架并遵循OOPS方法,因此一切都是类和对象。
  • Provides components - Wall, Shield and Guard. Components help modularize the application.

    提供组件-墙,盾和护罩。 组件有助于模块化应用程序。
  • Uses ES6 async/await or promise for executing asychronous code.

    使用ES6异步/等待或Promise执行异步代码。
  • Everything is configurable - you can configure your session store, view engine, websocket etc.

    一切都是可配置的-您可以配置会话存储,查看引擎,websocket等。
  • Dependency Injection.

    依赖注入。
  • Everything can be unit tested, so you can use a TDD approach.

    一切都可以进行单元测试,因此您可以使用TDD方法。

让我们编码 (Let's Code)

In this article I am going to create a REST API using FortJs and ES6. But you can use the same code and steps to implement using TypeScript too.

在本文中,我将使用FortJs和ES6创建REST API。 但是您也可以使用相同的代码和步骤来使用TypeScript实施。

项目设置 (Project Setup)

FortJs provides a CLI - fort-creator. This helps you set up the project and develop faster. Let's use the CLI to develop.

FortJs提供了一个CLI-堡垒创建者。 这可以帮助您设置项目并加快开发速度。 让我们使用CLI进行开发。

Perform the below steps sequentially:

依次执行以下步骤:

  • Open your terminal or command prompt.

    打开您的终端或命令提示符。
  • Install fort-creator globally - run the command "npm i fort-creator -g". Note: Make sure you have Nodejs installed in your system.

    全局安装Fort- creator-运行命令“ npm i fort-creator -g”。 注意:确保在系统中安装了Nodejs。

  • Create a new project - run the command "fort-creator new my-app". Here “my-app” is the name of the app, so you can choose any name. The CLI will prompt you to choose the language with two options: TypeScript and JavaScript. Choose your language by using the arrow keys and press enter - i have chosen JavaScript. It will take some time to create the project, so please wait until you see "new project my-app created".

    创建一个新项目-运行命令“ fort-creator new my-app”。 “ my-app”是应用程序的名称,因此您可以选择任何名称。 CLI将提示您选择带有两种选项的语言:TypeScript和JavaScript。 使用箭头键选择您的语言,然后按Enter键-我选择了JavaScript。 创建项目将需要一些时间,因此请等到看到“我的应用程序已创建新项目”。
  • Enter into the project directory - "cd my-app".

    进入项目目录-“ cd my-app”。

    Start the development server with live reloading - run the command "fort-creator start".

    通过实时重装启动开发服务器-运行命令“ fort-creator start”。

  • Open the browser and type the URL - http://localhost:4000/.

    打开浏览器并输入URL- http:// localhost:4000 /

    Open the browser and type the URL - http://localhost:4000/.

    打开浏览器,然后输入URL- http:// localhost:4000 /

You should see something like this in the browser.

您应该在浏览器中看到类似的内容。

Let's understand how this page is rendered:

让我们了解如何呈现此页面:

  • Open the project folder in your favourite code editor. I am going to use VS Code. You will see many folders inside project root such as controllers, views, etc. Every folder is grouped by their use - for example, the controllers folder contains all controllers and the views folder contains all views.

    在您喜欢的代码编辑器中打开项目文件夹。 我将使用VS Code。 您将在项目根目录中看到许多文件夹,例如controllers,views等。每个文件夹均按用途分组-例如,controllers文件夹包含所有控制器,而viewss文件夹包含所有视图。
  • Open the controllers folder -> Inside the controllers, you will see a file name - default_controller. Let's open it and observe the code. The file contains a class DefaultController - this is a controller class and it contains methods which return some http response.

    打开controllers文件夹-> controllers内部,您将看到一个文件名-default_controller。 让我们打开它并观察代码。 该文件包含一个DefaultController类-这是一个控制器类,它包含返回一些http响应的方法。

  • Inside the class DefaultController, you will see a method 'index' - this is the one which is rendering current output to the browser. The method is known as worker in FortJs because they do some kind of work and return the result as an http response. Let's observe the index method code:

    在类DefaultController内,您将看到一个方法'index'-这是一种将当前输出呈现给浏览器的方法。 该方法在FortJs中被称为worker ,因为它们进行某种工作并将结果作为http响应返回。 让我们观察一下索引方法代码:

    Inside the class DefaultController, you will see a method 'index' - this is the one which is rendering current output to the browser. The method is known as worker in FortJs because they do some kind of work and return the result as an http response. Let's observe the index method code:

    在类DefaultController内,您将看到一个方法'index'-这是一种将当前输出呈现给浏览器的方法。 该方法在FortJs中被称为worker ,因为它们进行某种工作并将结果作为http响应返回。 让我们观察一下索引方法代码:

    ```

    ```

    const data = {

    const data = {

       title: title

    标题:标题

    }

    }

    const result = await viewResult('default/index.html', data);

    const result = await viewResult('default / index.html',data);

    return result;

    返回结果;

    ```

    ```

    It creates a data object and passes that object into the

    它创建一个数据对象并将该对象传递到

    viewResult method. The viewResult method takes two parameters - the view location and view data. The work of viewResult is to render the view and return a response, which we are seeing in the browser.

    viewResult方法。 viewResult方法采用两个参数-视图位置和视图数据。 viewResult的工作是呈现视图并返回响应,我们正在浏览器中看到该响应。

  • Let's find the view code and understand it. Open the views folder - > open default folder - > open index.html. This is our view code. It is simple HTML code along with some mustache syntax. The default view engine for Fortjs is mustache.

    让我们找到视图代码并理解它。 打开views文件夹->打开默认文件夹->打开index.html。 这是我们的视图代码。 它是简单HTML代码以及一些胡须语法。 Fortjs的默认视图引擎是胡须。

I hope you have understood the project architecture. If you are having any difficulties or doubts, please feel free to ask in the comments section.

希望您了解项目架构。 如果您有任何困难或疑问,请随时在评论部分提问。

Now we will move to next part of this article where we will learn how to create a simple rest API.

现在,我们将转到本文的下一部分,在那里我们将学习如何创建一个简单的rest API。

休息 (REST)

We are going to create a REST endpoint for entity user - which will perform CRUD operations for the user such as adding a user, deleting a user, getting a user, and updating a user.

我们将为实体用户创建一个REST端点-它将为用户执行CRUD操作,例如添加用户,删除用户,获取用户和更新用户。

According to REST:

根据REST:

  1. Adding user - should be done using the http method "POST"

    添加用户-应该使用http方法“ POST ”完成

  2. Deleting user - should be done using the http method "REMOVE"

    删除用户-应该使用http方法“ REMOVE ”完成

  3. Getting user - should be done using the http method "GET"

    获取用户-应该使用http方法“ GET ”完成

  4. Updating user - should be done using the http method "PUT"

    更新用户-应该使用http方法“ PUT ”完成

For creating an endpoint, we need to create a Controller similar to the default controller explained earlier.

为了创建端点,我们需要创建一个类似于前面解释的默认控制器的Controller。

Execute the command  "fort-creator add". It will ask you to "Choose the component to add ?" Choose Controller & press enter. Enter the controller name "User" and press enter.

执行命令“ fort-creator add ”。 它将要求您“选择要添加的组件?” 选择控制器,然后按回车 。 输入控制器名称“用户”,然后按Enter

Now that we have created the user controller we need to inform FortJs by adding it to routes. The route is used to map our controller to a path.

现在,我们已经创建了用户控制器,我们需要通过将其添加到路由来通知FortJs。 该路线用于将我们的控制器映射到路径。

Since our entity is user, "/user" will be a good route. Let's add it. Open routes.js inside the root directory of the project and add UserController to routes.

由于我们的实体是用户,因此“ /user ”将是一个不错的选择。 让我们添加它。 在项目的根目录中打开routes.js,然后将UserController添加到路由中。

After adding UserController, routes.js will look like this:

添加UserController之后,routes.js将如下所示:

So when an http request has the path "/user" then UserController will be called.

因此,当http请求具有路径“ / user”时,将调用UserController。

Let's open the url - http://localhost:4000/user.

让我们打开url- http:// localhost:4000 / user

Note: If you have stopped FortJs while adding the controller, please start it again by running the cmd - fort-creator start

注意:如果添加控制器时已停止FortJs,请通过运行cmd重新启动-Fort fort-creator start

And you see a white page right?

然后您看到白页了吗?

This is because we are not returning anything from the index method and thus we get a blank response. Let's return a text "Hello World" from the index method. Add the below code inside the index method and save:

这是因为我们没有从index方法返回任何内容,因此我们得到了一个空白响应。 让我们从索引方法返回文本“ Hello World”。 将以下代码添加到index方法中并保存:

return textResult('Hello World');

Refresh the url - http://localhost:4000/user

刷新网址-http:// localhost:4000 / user

And you see "Hello World" right?

您看到“ Hello World”了吗?

Now, let's convert "UserController" to a REST API. But before writing code for the REST API, let's create a dummy service which will do CRUD operations for users.

现在,让我们将“ UserController”转换为REST API。 但是,在为REST API编写代码之前,让我们创建一个虚拟服务,该服务将为用户执行CRUD操作。

服务 (Service)

Create a folder called “services” and then a file “user_service.js” inside the folder. Paste the below code inside the file:

创建一个名为“ services”的文件夹,然后在该文件夹中创建一个文件“ user_service.js”。 将以下代码粘贴到文件中:

const store = {
    users: [{
        id: 1,
        name: "ujjwal",
        address: "Bangalore India",
        emailId: "ujjwal@mg.com",
        gender: "male",
        password: "admin"
    }]
}

export class UserService {
    getUsers() {
        return store.users;
    }

    addUser(user) {
        const lastUser = store.users[store.users.length - 1];
        user.id = lastUser == null ? 1 : lastUser.id + 1;
        store.users.push(user);
        return user;
    }

    updateUser(user) {
        const existingUser = store.users.find(qry => qry.id === user.id);
        if (existingUser != null) {
            existingUser.name = user.name;
            existingUser.address = user.address;
            existingUser.gender = user.gender;
            existingUser.emailId = user.emailId;
            return true;
        }
        return false;
    }

    getUser(id) {
        return store.users.find(user => user.id === id);
    }

    removeUser(id) {
        const index = store.users.findIndex(user => user.id === id);
        store.users.splice(index, 1);
    }
}

The above code contains a variable store which contains a collection of users. The method inside the service does operations like add, update, delete, and get on that store.

上面的代码包含一个变量存储,其中包含一组用户。 服务中的方法执行诸如添加,更新,删除以及在该商店上获取之类的操作。

We will use this service in REST API implementation.

我们将在REST API实现中使用此服务。

得到 (GET)

For the route "/user" with the http method "GET", the API should return a list of all users.

对于使用http方法“ GET”的路由“ / user”,API应该返回所有用户的列表。

In order to implement this, let's rename the "index" method inside user_controller.js to "getUsers" making it semantically correct. Then paste the below code inside the method:

为了实现这一点,让我们将user_controller.js中的“ index”方法重命名为“ getUsers”,使其在语义上正确。 然后将以下代码粘贴到方法中:

const service = new UserService();
return jsonResult(service.getUsers());

Now user_controller.js looks like this:

现在,user_controller.js如下所示:

import { Controller, DefaultWorker, Worker, textResult, jsonResult } from "fortjs";
import { UserService } from "../services/user_service";

export class UserController extends Controller {

    @DefaultWorker()
    async getUsers() {
        const service = new UserService();
        return jsonResult(service.getUsers());
    }
}

Here, we are using the decorator DefaultWorker. The DefaultWorker does two things: it adds the route "/" & the http method "GET". It's a shortcut for this scenario. In the next part, we will use other decorators to customize the route.

在这里,我们使用装饰器DefaultWorker。 DefaultWorker做两件事:添加路由“ /”和http方法“ GET”。 这是此方案的快捷方式。 在下一部分中,我们将使用其他装饰器来自定义路线。

Let's test this by calling the url http://localhost:4000/user. You can open this in the browser or use any http client tools like postman or curl.

让我们通过调用url http:// localhost:4000 / user进行测试 。 您可以在浏览器中打开它,也可以使用邮递员或curl等任何http客户端工具。

Ok, so we have successfully created an end point :) .

好的,我们已经成功创建了一个终点:)。

Let's look again at our code and see if we can make it better:

让我们再次看一下代码,看看是否可以做得更好:

  1. The service "UserService" is tightly coupled with Controller "UserController" which becomes a problem for unit testing "UserController". So we will use dependency injection by FortJs to inject UserService.

    服务“ UserService”与控制器“ UserController”紧密耦合,这成为单元测试“ UserController”的问题。 因此,我们将使用FortJs的依赖项注入来注入UserService。

  2. We are creating an instance of "UserService" every time the method getUsers is called. But what we need from "UserService" is a single object and then call the "UserService" method from the object.

    每次调用getUsers方法时,我们都会创建一个“ UserService”实例。 但是,我们从“ UserService”需要的是一个对象,然后从该对象调用“ UserService”方法。

So if we can somehow store an object of "UserService" then we can make our code faster (because calling new does some work under the hood). For this we will use the singleton feature of FortJs.

因此,如果我们可以某种方式存储“ UserService”的对象,则可以使我们的代码更快(因为调用new可以在后台进行某些工作)。 为此,我们将使用FortJs的单例功能。

Let's change the user_controller.js code by the below code:

让我们通过以下代码更改user_controller.js代码:

import { Controller, DefaultWorker, Worker, textResult, jsonResult, Singleton } from "fortjs";
import { UserService } from "../services/user_service";

export class UserController extends Controller {

    @DefaultWorker()
    async getUsers(@Singleton(UserService) service) {
        return jsonResult(service.getUsers());
    }
}

As you can see, the only change is that we are using the "Singleton" decorator in the method getUsers. This will create a singleton and inject that singleton when getUsers is called. This singleton will be available throughout the application.

如您所见,唯一的变化是我们在getUsers方法中使用了“ Singleton”装饰器。 这将创建一个单例并在调用getUsers时注入该单例。 该单例将在整个应用程序中可用。

Since service is now a parameter, we can manually pass the parameter while calling. This makes getUsers unit testable.

由于service现在是参数,因此我们可以在调用时手动传递参数。 这使getUsers单元可测试。

For doing unit testing or E2E testing, please read this test doc - http://fortjs.info/tutorial/test/

对于进行单元测试或E2E测试,请阅读此测试文档-http: //fortjs.info/tutorial/test/

开机自检 (POST)

Let's add a method "addUser" which will extract data from the request body and call service to add a user.

让我们添加一个方法“ addUser”,该方法将从请求主体中提取数据并调用服务以添加用户。

async addUser(@Singleton(UserService) service) {
        const user = {
            name: this.body.name,
            gender: this.body.gender,
            address: this.body.address,
            emailId: this.body.emailId,
            password: this.body.password
        };
        const newUser = service.addUser(user);
        return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}
In the above code we are creating the Singleton of the UserService again. So the question is will it create another object?
在上面的代码中,我们再次创建了UserService的Singleton。 那么问题是它将创建另一个对象吗?

No it will be same object that was in getUser. FortJs supplies the object as a parameter when it calls the method.

不,它将是与getUser中相同的对象。 FortJs在调用方法时将其作为参数提供。

The methods created are by default not visible for an http request. So in order to make this method visible for the http request, we need to mark this as a worker.

默认情况下,创建的方法对于http请求不可见。 因此,为了使该方法对于http请求可见,我们需要将此方法标记为工作程序。

A method is marked as a worker by adding the decorator "Worker". The Worker decorator takes a list of http methods and makes that method available for only those http methods. So let's add the decorator:

通过添加装饰器“ Worker”将方法标记为工作器。 Worker装饰器获取HTTP方法列表,并使该方法仅可用于那些http方法。 因此,让我们添加装饰器:

@Worker([HTTP_METHOD.Post])
async addUser(@Singleton(UserService) service) {
    const user = {
        name: this.body.name,
        gender: this.body.gender,
        address: this.body.address,
        emailId: this.body.emailId,
        password: this.body.password
    };
    const newUser = service.addUser(user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}

Now the route of this method is the same as the name of the method that is "addUser". You can check this by sending a post request to http://localhost:4000/user/addUser with user data in the body.

现在,此方法的路由与方法名称“ addUser”相同。 您可以通过向正文中包含用户数据的http:// localhost:4000 / user / addUser发送发帖请求来进行检查。

But we want the route to be "/", so that it will be a rest API. The route of the worker is configured by using the decorator "Route". Let's change the route now.

但是我们希望路由为“ /”,因此它将是一个REST API。 使用装饰器“ Route”配置工作进程的路由。 让我们现在更改路线。

@Worker([HTTP_METHOD.Post])
@Route("/")
async addUser(@Singleton(UserService) service) {
    const user = {
        name: this.body.name,
        gender: this.body.gender,
        address: this.body.address,
        emailId: this.body.emailId,
        password: this.body.password
    };
    const newUser = service.addUser(user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}

Now our end point is configured for a post request. Let's test this by sending a post request to http://localhost:4000/user/ with user data in the body.

现在,我们的端点已配置为发布请求。 让我们通过在正文中发送用户数据到http:// localhost:4000 / user /来发送发布请求,以进行测试。

It returns the user created with id which is our logic. So we have created the end point for the post request, but one important thing to do is to validate the data. Validation is an essential part of any app and is very important for a backend application.

它返回使用id创建的用户,这是我们的逻辑。 因此,我们为发布请求创建了终点,但是要做的一件事是验证数据。 验证是任何应用程序的重要组成部分,对于后端应用程序非常重要。

So far, our code is clean and readable. But if we add validation code it will become a little dirty.

到目前为止,我们的代码是清晰易读的。 但是,如果我们添加验证代码,它将变得有点脏。

Worry not, FortJs provides the component Guard for this kind of work. A/c to the FortJs docs:

不用担心,FortJs为此类工作提供了Guard组件。 FortJs文档的A / c:

Guard is security layer on top of Worker. It controls whether a request should be allowed to call the Worker.
Guard是Worker之上的安全层。 它控制是否应允许请求调用Worker。

So we are going to use guard for validation of the data. Let's create the guard using fort-creator. Execute the command  fort-creator add and choose Guard. Enter the file name "UserValidator". There will be a file "user_validator_guard.js" created inside the guards folder. Open that file.

因此,我们将使用Guard来验证数据。 让我们使用堡垒创造者创建守卫。 执行命令fort-creator add并选择Guard。 输入文件名“ UserValidator”。 在guards文件夹中将创建一个文件“ user_validator_guard.js”。 打开该文件。

A guard has access to the body, so you can validate the data inside that. Returning null inside the method check means that we're allowing to call the worker. Returning anything else means block the call.

守卫可以进入尸体,因此您可以验证其中的数据。 在方法check返回null意味着我们允许调用工作程序。 返回其他任何内容均表示阻止通话。

Let's make it clearer by writing code for the validation. Paste the below code inside the file "user_validator_guard.js":

让我们通过编写验证代码来使其更加清晰。 将以下代码粘贴到文件“ user_validator_guard.js”中:

import { Guard, textResult, HTTP_STATUS_CODE } from "fortjs";

export class UserValidatorGuard extends Guard {

    async check() {
        const user = {
            name: this.body.name,
            gender: this.body.gender,
            address: this.body.address,
            emailId: this.body.emailId,
            password: this.body.password
        };
        const errMsg = this.validate(user);
        if (errMsg == null) {
            // pass user to worker method, so that they dont need to parse again  
            this.data.user = user;
            // returning null means - guard allows request to pass  
            return null;
        } else {
            return textResult(errMsg, HTTP_STATUS_CODE.BadRequest);
        }
    }
    
    validate(user) {
        let errMessage;
        if (user.name == null || user.name.length < 5) {
            errMessage = "name should be minimum 5 characters"
        } else if (user.password == null || user.password.length < 5) {
            errMessage = "password should be minimum 5 characters";
        } else if (user.gender == null || ["male", "female"].indexOf(user.gender) < 0) {
            errMessage = "gender should be either male or female";
        } else if (user.emailId == null || !this.isValidEmail(user.emailId)) {
            errMessage = "email not valid";
        } else if (user.address == null || user.address.length < 10) {
            errMessage = "address length should be greater than 10";
        }
        return errMessage;
    }
    
    isValidEmail(email) {
        var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return re.test(String(email).toLowerCase());
    }


}

In the above code:

在上面的代码中:

  • We have created a method validate which takes the parameter user. It validates the user & returns the error message if there is a validation error, otherwise null.

    我们创建了一个方法validate,它使用参数user。 它会验证用户并在出现验证错误时返回错误消息,否则返回null。
  • We are validating data inside the check method, which is part of guard lifecycle. We are validating the user inside it by calling the method validate.

    我们正在检查方法内部的数据,这是保护生命周期的一部分。 我们通过调用validate方法来验证其中的用户。

    If the user is valid, then we are passing the user value by using the "data" property and returning null. Returning null means guard has allowed this request and the worker should be called.

    如果用户有效,那么我们通过使用“ data”属性并返回null来传递用户值。 返回null表示Guard已允许此请求,并且应调用worker。

  • If a user is not valid, we are returning an error message as a text response with the HTTP code "Bad Request". In this case, execution will stop here and the worker won't be called.

    如果用户无效,我们将以HTTP代码“错误请求”的形式返回错误消息作为文本响应。 在这种情况下,执行将在此处停止,并且不会调用该工作程序。

In order to activate this guard for the method addUser, we need to add this on top of addUser. The guard is added by using the decorator "Guards". So let's add the guard:

为了激活方法addUser的此保护,我们需要将其添加到addUser之上。 通过使用装饰器“ Guards”来添加防护罩。 因此,让我们添加防护:

@Worker([HTTP_METHOD.Post])
@Route("/")
@Guards([UserValidatorGuard])
async addUser(@Singleton(UserService) service) {
    const newUser = service.addUser(this.data.user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}

In the above code:

在上面的代码中:

  • I have added the guard, “UserValidatorGuard” using the decorator Guards.

    我已经使用装饰器Guards添加了防护“ UserValidatorGuard”。
  • With the guard in the process, we don't need to parse the data from the body anymore inside the worker. Rather, we are reading it from this.data which we are passing from "UserValidatorGuard".

    有了后卫,我们就不再需要在工人内部解析来自身体的数据。 而是从“ UserValidatorGuard”传递的this.data中读取它。
  • The method “addUser” will only be called when Guard allows, which means all data is valid.

    仅当Guard允许时才调用方法“ addUser”,这意味着所有数据均有效。

One thing to note is that the method "addUser" looks very light after using a component, and it's doing validation too. You can add multiple guards to a worker which gives you the ability to modularize your code into multiple guards and use that guard at multiple places.

需要注意的一件事是,使用组件后,方法“ addUser”看起来非常轻巧,它也在进行验证。 您可以向工作人员添加多个防护,这使您能够将代码模块化为多个防护,并在多个位置使用该防护。

Isn't this cool :D?
:D这不是很酷吗?

Let's try adding a user with some invalid data:

让我们尝试为用户添加一些无效数据:

As you can see in the screenshot, I have tried sending a request without a password. The result is - "password should be minimum 5 characters". So it means that guard is activated and working perfectly.

如您在屏幕截图中所见,我尝试发送没有密码的请求。 结果是-“密码应至少为5个字符”。 因此,这意味着防护装置已启动且工作正常。

(PUT)

Let’s add another method - “updateUser” with route “/” , guard “UserValidatorGuard” (for validation of user) and most important - worker with http method “PUT”.

让我们添加另一种方法-带有路由“ /”的“ updateUser”,保护“ UserValidatorGuard”(用于验证用户)以及最重要的-使用http方法“ PUT”的worker。

@Worker([HTTP_METHOD.Put])
@Guards([UserValidatorGuard])
@Route("/")
async updateUser(@Singleton(UserService) service) {
    const user = this.data.user;
    const userUpdated = service.updateUser(user);
    if (userUpdated === true) {
        return textResult("user updated");
    } else {
        return textResult("invalid user");
    }
}

The updated code is similar to the addUser code except functionality wise it is updating the data. Here, we have reutilized UserValidatorGuard to validate data.

更新的代码与addUser代码类似,不同之处在于功能是在更新数据。 在这里,我们重新利用了UserValidatorGuard来验证数据。

删除 (DELETE)

In order to delete data, user needs to pass the id of the user. This can be passed by:

为了删除数据,用户需要传递用户的ID。 这可以通过:

  • Sending data in body just like we did for add & update - {id:1}

    就像我们进行添加和更新一样,在正文中发送数据-{id:1}
  • Sending data in query string - ?id=1

    以查询字符串发送数据-?id = 1
  • Sending data in route - for this, we need to customize our route - "/user/1"

    在路由中发送数据-为此,我们需要自定义路由-“ / user / 1”

We have already implemented getting data from body. So let's see other two ways:

我们已经实现了从身体获取数据。 因此,让我们看看另外两种方式:

Sending Data in Query String

以查询字符串发送数据

Let's create a method "removeByQueryString" and paste the below code:

让我们创建一个方法“ removeByQueryString”并粘贴以下代码:

@Worker([HTTP_METHOD.Delete])
@Route("/")
async removeByQueryString(@Singleton(UserService) service) {
    // taking id from query string
    const userId = Number(this.query.id);
    const user = service.getUser(userId);
    if (user != null) {
        service.removeUser(userId);
        return textResult("user deleted");
    } else {
        return textResult("invalid user", 404);
    }
}

Sending Data in Route

在路线中发送数据

You can parameterise the route by using "{var}" in a route. Let's see how.

您可以通过在路由中使用“ {var}”来参数化路由。 让我们看看如何。

Let's create another method "removeByRoute" and paste the below code:

让我们创建另一个方法“ removeByRoute”并粘贴以下代码:

@Worker([HTTP_METHOD.Delete])
@Route("/{id}")
async removeByRoute(@Singleton(UserService) service) {
    
    // taking id from route
    const userId = Number(this.param.id);

    const user = service.getUser(userId);
    if (user != null) {
        service.removeUser(userId);
        return textResult("user deleted");
    } else {
        return textResult("invalid user");
    }
}

The above code is exactly the same as removeByQueryString except that it is extracting the id from the route and using parameter in route i.e., "/{id}" where id is parameter.

上面的代码与removeByQueryString完全相同,只不过它是从路由中提取ID并在route中使用参数,即“ / {id}”,其中id为参数。

Let's test this:

让我们测试一下:

So we have finally created a REST API for all the funtionalities except GETting a particular user by id. I will leave that to you for practice.

因此,我们终于为所有功能创建了REST API,除了通过id获取特定用户外。 我会把它留给您练习。

兴趣点 (POINTS OF INTEREST)

Q: How do we add authentication to "UserController", so that any unauthenticated request can't call the "/user" end point.

问:我们如何向“ UserController”添加身份验证,以使任何未经身份验证的请求都不能调用“ / user”端点。

A: There are multiple approaches for this:

答:有多种解决方法:

  • We can check in every worker for authentication. (BAD - so much extra work and code repetition)

    我们可以签入每个工作人员进行身份验证。 (糟糕-太多的额外工作和代码重复)
  • Create a Guard component and assign to every worker . (GOOD)

    创建一个Guard组件并分配给每个工作人员。 (好)
  • Create a Shield component and assign to controller. Shield is a security layer similar to guard but works on top of controller, so if shield rejects then controller is not initiated. (BEST)

    创建一个Shield组件并分配给控制器。 Shield是类似于防护的安全层,但在控制器之上起作用,因此,如果Shield拒绝,则不会启动控制器。 (最好)

Take a look at the FortJs authentication docs - http://fortjs.info/tutorial/authentication/

看看在FortJs认证文档- http://fortjs.info/tutorial/authentication/

参考资料 (REFERENCES)

翻译自: https://www.freecodecamp.org/news/nodejs-development-with-modern-javascript-using-fortjs/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值