如何将JOI validator作为中间件添加到Firebase function中?
解决方案
Firebase HTTPS Callable 函数的处理函数接收的是(data, context)两个参数,而非Express的(req, res),原Express的Joi中间件无法直接复用,我们可以通过高阶校验包装函数实现类似的中间件效果,原有业务逻辑完全不需要修改。
步骤1:定义通用Joi校验包装函数
const Joi = require('joi'); // 若使用v2版本firebase-functions,导入方式如下: const { HttpsError } = require('firebase-functions/v2/https'); // 若使用v1版本firebase-functions,替换为下面的导入: // const functions = require('firebase-functions'); // const HttpsError = functions.https.HttpsError; // 通用Joi校验高阶函数,入参为校验规则schema、原业务处理函数 const validateJoi = (schema, handler) => { return async (data, context) => { // abortEarly设为false可返回所有校验不通过的字段提示,默认仅返回第一个 const { error } = schema.validate(data, { abortEarly: false }); if (error) { // 抛出Firebase标准HTTPS错误,客户端可正常识别错误信息 throw new HttpsError( 'invalid-argument', '参数校验不通过', error.details.map(item => item.message) ); } // 校验通过,执行业务逻辑 return handler(data, context); }; };
步骤2:定义业务对应的Joi校验Schema
以创建用户账号场景为例:
const createUserSchema = Joi.object({ email: Joi.string().email().required().messages({ 'string.email': '邮箱格式不正确', 'any.required': '邮箱为必填项' }), password: Joi.string().min(6).required().messages({ 'string.min': '密码长度不能少于6位', 'any.required': '密码为必填项' }), nickname: Joi.string().max(20).optional() });
步骤3:包装原业务函数注册到Firebase云函数
// 原createAccount函数完全保持不变,不需要修改任何逻辑 const createAccount = async (data, context) => { // 你的原有业务逻辑 return { success: true, userId: 'xxxx' }; }; // 注册云函数时用validateJoi包装原函数即可 exports.createUserAccount = region("europe-east1") .https .onCall(validateJoi(createUserSchema, createAccount));
额外说明
- 如果只有单个函数需要校验,不需要复用逻辑,也可以直接在
createAccount函数开头调用Joi校验逻辑,不需要单独封装高阶函数 - 校验失败抛出的
HttpsError会被Firebase自动处理,返回对应错误码和信息给调用端,不需要自己构造返回值
内容的提问来源于stack exchange,提问作者markWanka
相关产品推荐
相关产品推荐

