您当前的位置: 首页 > 

寒冰屋

暂无认证

  • 0浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

NodeJs开发框架fortjs

寒冰屋 发布时间:2019-06-18 17:49:47 ,浏览量:0

目录

介绍

背景

使用代码

项目设置

兴趣点

参考

  • 下载源代码 - 60.8 KB
介绍

Nodejs使您能够使用JavaScript编写服务器端代码。实际上,使用nodejs创建Web服务器非常容易和快速,并且构建了许多框架,这使得开发更加容易和快速。

但Nodejs的发展面临的挑战并不多:

  • Node js都是关于回调的,并且随着越来越多的回调,你最终会遇到一个叫做回调地狱的情况
  • 编写可读代码
  • 编写可维护的代码
  • 你没有得到太多智能感知支持,这使得开发变得缓慢

如果您有经验并且对nodejs有很好的了解,那么您可以使用不同的技术并尽量减少这些挑战。

解决这些问题的最佳方法是使用现代JavaScript ES6,ES7或typescript,无论您感觉如何。我推荐使用typescript,因为它为每个代码字提供了intillisense支持,使您的开发更快。

所以我找到了一个框架fortjs——它非常易于使用,其概念非常酷。它的概念围绕创造一个堡垒。Fortjs使您能够编写模块化、安全且非常漂亮且可读的服务器端代码。

背景

FortJs是一个MVC框架,其工作方式类似于真正的堡垒。它以组件的形式提供模块化。有三个组成部分:

  1. Wall——这是一个顶级组件,每个HTTP请求首先通过wall。
  2. Shield——这适用于控制器。您可以为控制器分配一个shield,它将在调用控制器之前执行。
  3. Guard——这适用于fort.js中名为worker的控制器内部的方法。在调用worker之前,将调用guard。

每个组件都像一个阻塞程序,如果条件不满足——它们会阻止请求进一步传递。就像在一个真正的堡垒——如果条件不满意,警卫会阻止任何人。

我希望您理解这一点并获取更多信息,请阅读组件文档——http://fortjs.info/tutorial/components/。

使用代码

在本文中 - 我将使用fortjs和typescript语言创建REST API。但您也可以使用相同的代码和步骤用JavaScript来实现。

项目设置

FortJs提供了一个CLI——fort-creator。这有助于您设置项目并加快开发速度。我也将使用CLI。

因此,按顺序执行以下步骤:

  • 打开终端或命令提示符。
  • 全局安装FortJs——运行命令“npm i fort-creator -g”。
  • 创建一个新项目——运行命令“fort-creator new my-app”。这里“my-app”是应用程序的名称,您可以选择任何其他名字。这将提示您选择具有两个选项的语言:typescript和javascript。使用箭头键选择语言,然后按Enter键。因为我要使用typescript,所以我选择了typescript。创建项目需要一些时间。
  • 进入项目目录——“cd my-app”。
  • 使用热重新加载启动开发服务器——运行命令“ fort-creator start”。
  • 打开浏览器并输入URL——http://localhost:4000/.。

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

让我们看看如何呈现此页面:

  • 在您喜欢的代码编辑器中打开项目文件夹,我将使用vscode。您将在项目根目录中看到许多文件夹,例如控制器,视图等。每个文件夹按其用途分组,例如controllers文件夹包含所有控制器和视图文件夹包含所有视图。
  • 打开控制器文件夹 ->在控制器内部,您将看到一个文件名——default_controller,让我们打开它并观察代码。该文件包含一个类DefaultController——这是一个控制器类,它包含返回一些http响应的方法。
  • 在DefaultController类中->您将看到一个方法'index'——这是将输出呈现给浏览器的方法。该方法在fortjs中称为worker,因为它们执行某种工作并将结果作为http响应返回。让我们观察index方法代码:
try {
    const data= {
        title: 'FortJs'
    };
    const result = await viewResult('default/index.html', data);
    return result;
} catch (ex) {
    // handle exception and show user a good message.
    // save this ex in a file or db, so that you can know what's the issue and where
    const result = await textResult("Our server is busy right now. Please try later.");
    return result;
}

它创建一个数据对象并将该对象传递给viewResult方法。该viewResult方法获取视图位置和视图数据。此方法的工作是呈现我们在浏览器中看到的视图和返回响应。

  • 我们来观察一下视图代码。打开视图文件夹 ->打开默认文件夹 ->打开index.html。这是我们的视图代码。它是简单的HTML代码以及一些mustache 语法。Fortjs默认视图引擎是mustache 。

REST

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

根据REST:

  1. 添加用户——应该使用http方法“POST”
  2. 删除用户——应该使用http方法“REMOVE”
  3. 获取用户——应该使用http方法完成“GET”
  4. 更新用户——应该使用http方法“PUT”

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

执行命令——“fort-creator add”。它会询问“what do you want to add ?”选择控制器并按回车键。输入控制器名称“UserController”并按Enter键。

现在我们已经创建了用户控制器,我们需要将它添加到路由中。由于我们的实体是用户,因此“/user”将是一条很好的路由。让我们添加它——在项目的根目录中打开routes.ts并添加UserController到路由。

所以我们的routes.ts看起来像这样:

import { DefaultController } from "./controllers/default_controller";
import { ParentRoute } from "fortjs";
import { UserController } from "./controllers/user_controller";

export const routes: ParentRoute[] = [{
    path: "/default",
    controller: DefaultController
}, {
    path: "/user",
    controller: UserController
}];

现在fortjs知道当路由——“/user ”被调用时,它需要调用UserController。让我们打开网址——http://localhost:4000/user。

你看到一个白页了吗?

这是因为——我们没有从index方法返回任何东西。让我们从index方法中返回一个文本“Hello World”。在index方法内添加以下代码并保存:

return textResult('Hello World');

刷新URL—— http://localhost:4000/user

而且你将看Hello World。

现在,让我们转换UserController为REST API。但在编写REST API代码之前,让我们创建一个虚拟服务,为用户进行crud操作。

MODEL

让我们创建一个代表实体用户的模型“User”。创建一个文件夹models和在文件夹内的文件user.ts。将以下代码粘贴到文件中:

export class User {
    id?: number;
    name: string;
    gender: string;
    address: string;
    emailId: string;
    password: string;
    
    constructor(user) {
        this.id = Number(user.id);
        this.name = user.name;
        this.gender = user.gender;
        this.address = user.address;
        this.emailId = user.emailId;
        this.password = user.password;
    }
}

SERVICE

创建文件夹“services ”,然后在文件夹中创建文件“user_service.ts ”。将以下代码粘贴到文件中。

import {
    User
} from "../models/user";

interface IStore {
    users: User[]
};
const store: IStore = {
    users: [{
        id: 1,
        name: "durgesh",
        address: "Bengaluru india",
        emailId: "durgesh@imail.com",
        gender: "male",
        password: "admin"
    }]
}

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

    addUser(user: 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);
    }
}

上面的代码包含一个变量存储,它包含一组用户,服务中的方法执行添加、更新、删除和获取该存储等操作。

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

REST

GET

对于使用http方法“ GET”的路由“/user ”,API应返回所有用户的列表。为了实现这一点,让我们将“index”方法重命名为“getUsers”以使语义正确并将以下代码粘贴到方法中:

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

所以现在,user_controller.ts看起来像这样:

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());
    }
}

在这里,我们正在使用装饰器DefaultWorker。DefaultWorker做两件事情-它增加了路由“/”与HTTP方法“GET”。它是这种情况的捷径。在下一部分中,我们将使用其他装饰器来自定义路径。

让我们通过调用url http://localhost:4000/user来测试它。您可以在浏览器中打开它或使用任何http客户端工具,如postman或高级REST客户端。我正在使用高级REST客户端。

POST

让我们添加一个方法“addUser”,它将从请求体中提取数据并添加用户。

async addUser() {
    const user: User = {
        name: this.body.name,
        gender: this.body.gender,
        address: this.body.address,
        emailId: this.body.emailId,
        password: this.body.password
    };
    const service = new UserService();
    const newUser = service.addUser(user);
    return jsonResult(newUser, HTTP_STATUS_CODE.Created);
}

为了使这个方法对http请求可见,我们需要将其标记为worker。通过添加装饰器“Worker” 将方法标记为worker 。Worker装饰采用HTTP方法列表,并使该方法仅对那些HTTP方法可用。那么让我们添加装饰器:

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

此方法的路由与“addUser” 方法的名称相同。您可以通过将post请求发送到 http://localhost:4000/user/addUser并在body中包含用户数据来检查这一点。

但我们希望路由为“/”,因此它是一个RESTAPI。使用装饰器“Route” 配置worker的路径。我们现在改变路由。

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

现在我们的终点配置为post请求。让我们通过将post请求发送到 http://localhost:4000/user/addUser并在body中包含用户数据来检查这一点。

我们已经为post请求创建了终点,但重要的是要验证数据。验证是服务器端Web应用程序中非常重要的一部分。

FortJs为这类工作提供组件Guard。

引用:

Guard是Worker上的安全层。它控制是否允许请求调用Worker。

所以我们将使用guard来验证数据。让我们用fort-creator来创造一个guard。执行命令——“fort-creator add”并选择Guard。输入文件名“UserValidatorGuard ”。将在guards文件夹中创建一个“user_validator_guard.ts ” 文件,打开该文件。

guard可以访问正文,因此您可以验证其中的数据。返回null内部方法检查意味着允许调用worker & 返回任何其他内容意味着阻止调用。

让我们通过编写验证代码来更深入地理解这一点。将以下代码粘贴到文件“user_validator_guard.ts”中:

import { Guard, HTTP_STATUS_CODE, textResult } from "fortjs";
import { User } from "../models/user";

export class UserValidatorGuard extends Guard {

    isValidEmail(email: string) {
        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());
    }

    validate(user: 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;
    }

    async check() {
        const user = new User(this.body);
        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 - this guard allows request to pass  
            return null;
        } else {
            return textResult(errMsg, HTTP_STATUS_CODE.BadRequest);
        }
    }
}

在上面的代码中:

  • 我们创建了一个带参数用户的方法validate。如果存在验证错误,它将验证用户并返回错误消息,否则返回null。
  • 我们在check方法中编写代码,这是守护生命周期的一部分。我们通过调用validate方法验证其中的用户。
  • 如果用户有效,那么我们使用“data”属性传递用户值并返回null。返回null意味着guard已允许此请求,应该调用worker。
  • 如果用户无效,我们将返回错误消息作为带有HTTP代码的文本响应——“badrequest”。在这种情况下,执行将在此处停止并且不会调用worker。

为了激活这个guard,我们需要为addUser方法添加它。通过使用装饰器“Guards”添加guard。所以让我们加上guard:

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

在上面的代码中:

  • 我已经使用Guards装饰器添加了guard ,“UserValidatorGuard”。
  • 有了这个过程中的guard,我们不再需要在worker内部解析来自body的数据,而是从“ModelUserGuard”传递的this.data中读取数据。
  • addUser只有当所有数据都有效时,才会调用方法“Guard” 。

需要注意的一点是——使用组件后方法“addUser”看起来很轻量 & 它也在进行验证。您可以向工作人员添加多个guard,使您能够将代码模块化为多个guard。

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

正如您在图片中看到的,我尝试发送无效的电子邮件,结果是——“email not valid”。所以它意味着guard被激活并且完美地工作。

PUT

让我们添加另一种方法——用路由“/”的“updateUser”, guard——“ UserValidatorGuard”(用于验证用户)和最重要的——用http方法“PUT”的worker。

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

更新代码类似于插入代码,除了正在更新数据的功能。在这里,我们重新使用UserValidatorGuard以验证数据。

DELETE

为了删除数据,用户需要传递用户的id。这可以通过三种方式传递:

  • 正如我们为添加和更新所做的那样在正文中发送数据
  • 在查询字符串中发送数据
  • 在路由中发送数据——为此,我们需要自定义路由

我们已经实现了从body获取数据。那么让我们看看另外两种方式:

在查询字符串中发送数据

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

@Worker([HTTP_METHOD.Delete])
@Route("/")
async removeByQueryString() {
    // taking id from query string
    const userId = Number(this.query.id);

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

上面的代码非常简单。它从query控制器的属性获取id 并删除用户。我们来测试一下:

在路由中发送数据

您可以在路径中使用“{var}”来参数化路由。我们来看看怎么样?

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

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

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

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

我们来测试一下:

因此,我们使用fortjs成功创建了REST API。

兴趣点

为fortjs编写的代码清晰、可读和可维护。这些组件可帮助您模块化代码。

参考
  1. http://fortjs.info/
  2. https://medium.com/fortjs/rest-api-using-typescript-94004d9ae5e6

 

原文地址:https://www.codeproject.com/Articles/5098856/NodeJs-Development-with-framework-fortjs

关注
打赏
1665926880
查看更多评论
立即登录/注册

微信扫码登录

0.1043s