koa教程2 用户注册及Joi校验、成功信息返回
用户注册
用户数据表搭建完毕后,我们肯定是需要注册用户的,那么首先我们需要创建一个路由api了。
在根目录:/app/router/v1
目录下创建一个user.js
文件。
user.js:
const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
//注册用户
router.post("/register", async (ctx, next) => {
});
module.exports = router;
注意:记得在app.js中删除上一节require("./models/user")
代码,因为已经不需要了,我们这这里使用了。
假设客户端传来的数据如下:ctx.body
{
email: "1321968423@qq.com",
password1: "123456",
password2: "123456",
nickname: "木灵鱼儿"
}
那么我们要对这个参数进行校验
参数校验
通过ctx.body我们可以拿到客户端传过来的数据。为此在校验前我们需要安装Joi
yarn add joi --dev
joi如何校验数据?
首先我们需要通过Joi.object()
创建一个参数校验对象A,然后通过这个参数校验对象A的validateAsync
方法,将ctx.body传入,然后joi就会根据我们的设定进行参数校验,不通过将会抛出Error错误对象。
成功,则是会返回被检验的参数,注意,这个参数可以在校验时改动,比如一个参数首尾代空格,我们可以通过joi将首尾空格去除,然后在存入数据库中。
joi默认是自动创建Error对象的,这个错误最终会被我们全局错误捕获所捕获,但是这个Error并没有我们需要参数,所以,我们需要控制joi的错误对象为我们自定义的错误对象才行,好在这个行为我们是可以控制的。
创建校验失败的错误对象
http-error.js:
//基础错误对象
class HttpError extends Error {
constructor(msg = "服务器异常", errorCode = 10000, status = 400) {
super();
this.errorCode = errorCode;
this.status = status;
this.msg = msg;
}
};
//校验不通过的错误对象
class ValidateError extends HttpError {
constructor(msg, errorCode) {
super();
this.errorCode = errorCode || 10001;
this.status = 200;
this.msg = msg || "参数检验不通过!";
}
};
module.exports = {
HttpError,
ValidateError,
};
ValidateError 将是我们参数校验不通过所使用的错误对象,他的状态是200,访问是成功地。
创建创建用户校验方法
在utils目录下,创建一个validate目录,里面用于存放我们校验的方法,在validate中创建user.js
文件
user.js:
const Joi = require("joi");
const { ValidateError } = require(`${process.cwd()}/core/http-error`);
const { User } = require(`${process.cwd()}/models/user`);
//验证数据库是否已经有相同邮箱
const isExistSameEmail = async (email) => {
const user = await User.findOne({
where: { email }
});
//查不到返回null
if (user) throw new ValidateError("邮箱已存在!");
return email; //可以在这改变返回值
};
//注册账号
const registerValidate = (data) => {
const joiObject = Joi.object({
//最低2位邮箱@后面的内容,例:@io
email: Joi.string().email({ minDomainSegments: 2 })
.required().external(isExistSameEmail, "是否存在相同邮箱")
.error(new ValidateError("邮箱不合法!")),
//password 密码必填 6-32位
password1: Joi.string().trim(true).min(6).max(32).required()
.error(new ValidateError("密码必须是1-32位!")),
//二次检验密码
password2: Joi.string().valid(Joi.ref("password1"))
.error(new ValidateError("两次密码必须相同!")),
//昵称 最低2位
nickname: Joi.string().trim(true).pattern(new RegExp("^[^\\s]+$")).min(2)
.error(new ValidateError("昵称长度最低2位且不能包含空格!")),
});
return joiObject.validateAsync(data);
};
module.exports = {
registerValidate
}
具体用法就自己查看joi的文档了,https://joi.dev/api/?v=17.4.0,目前最新是17版本
其中trim(true)
是可以去除参数首尾空格。
external表示自定义异步校验,所以他被安排到了最后校验,所以如果在external中对参数进行操作,其他校验器是拿不到的,正因为他是异步的,所以我们在里面使用异步的请求,比如上面对数据进行查询,如果有相同的email就抛出错误。
external接受两个参数,一个要出触发的函数,另一个是说明文字。
如果是一个比较简单的校验,同步就能完成的,我们可以使用custom的方式,他的用法和external差不多,也是两个参数,函数和说明文字,只是他里面不用使用异步的方法。
开始校验
user.js:
const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);
//注册用户
router.post("/register", async (ctx, next) => {
//验证
const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
// 验证通过
console.log("验证通过")
});
module.exports = router;
当他能往下走的时候,说明验证已经通过了,我们就可以往数据库写入内容,写入内容我们也需要引入对象的模型。
const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);
const { User } = require(`${process.cwd()}/models/user`);
//注册用户
router.post("/register", async (ctx, next) => {
//验证
const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
//验证通过加入数据库
await User.create({ email, password, nickname });
});
module.exports = router;
写入数据后我们还需要返回给前端成功的信息。
成功信息返回
返回信息很多人可能是这样写:
ctx.body = {
msg: xxxx,
....
}
如果每个接口都这样写是不是太累了,对象的格式都是一样的,返回的一些状态值也是一样的。
我们可以创建一个用于返回成功信息的错误对象,这样就能被全局错误捕获所捕获,然后返回给前端。
于是乎:
http-error.js:
//基础错误对象
class HttpError extends Error {
constructor(msg = "服务器异常", errorCode = 10000, status = 400) {
super();
this.errorCode = errorCode;
this.status = status;
this.msg = msg;
}
};
//校验不通过的错误对象
class ValidateError extends HttpError {
constructor(msg, errorCode) {
super();
this.errorCode = errorCode || 10001;
this.status = 200;
this.msg = msg || "参数检验不通过!";
}
};
//成功的错误对象
class Success extends HttpError {
constructor(msg, errorCode) {
super();
this.errorCode = errorCode || 2000;
this.status = 201;
this.msg = msg || "参数检验不通过!";
}
}
module.exports = {
HttpError,
ValidateError,
Success
};
在路由里面使用:
const Router = require("koa-router");
const router = new Router({ prefix: "/v1/user" });
const { User } = require(`${process.cwd()}/models/user`);
const { registerValidate } = require(`${process.cwd()}/utils/validate/user`);
const { User } = require(`${process.cwd()}/models/user`);
const { Success } = require(`${process.cwd()}/core/http-error`);
//注册用户
router.post("/register", async (ctx, next) => {
//验证
const { email, password1: password, nickname } = await registerValidate(ctx.request.body);
//验证通过加入数据库
await User.create({ email, password, nickname });
throw new Success("账号创建成功!");
});
module.exports = router;
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据