TypeScript嵌套JSON(含数组)通用属性过滤中间件实现咨询
基于TypeScript的通用REST API响应字段过滤中间件实现方案
核心开发目标
- 开发基于TypeScript的REST API响应处理中间件
- 核心能力为对接口返回的JSON数据做属性过滤,仅返回用户指定字段
- 满足强通用性要求:不依赖具体业务实体的结构定义,无需提前知晓实体的属性构成、嵌套深度,可适配任意数量的关联关系层级
典型应用场景示例
以「作者-文章-评论」的多层关联结构为例,单个作者可关联任意数量的文章,每篇文章可关联任意数量的评论,原始返回的JSON数据结构如下:
[ { "name": "John Doe", "email": "john@doe.com", "articles": [ { "title": "Lalilu 1", "text:": "la li lu", "comments": [ { "author": "Bendthatdict Cumberstone", "text": "Great article!" }, { "author": "Bendthatdict Cumberstone", "text": "Great article!" } ] }, { "title": "Lalilu 1", "text": "la li lu", "comments": [ { "author": "Bendthatdict Cumberstone", "text": "Great article!" }, { "author": "Bendthatdict Cumberstone", "text": "Great article!" } ] } ] }, { "name": "Jane Doe", "email": "jane@doe.com", "articles": [ { "title": "Lalilu 1", "text": "la li lu", "comments": [ { "author": "Bendthatdict Cumberstone", "text": "Great article!" }, { "author": "Bendthatdict Cumberstone", "text": "Great article!" } ] }, { "title": "Lalilu 1", "text": "la li lu", "comments": [ { "author": "Bendthatdict Cumberstone", "text": "Great article!" }, { "author": "Bendthatdict Cumberstone", "text": "Great article!" } ] } ] } ]
预期调用与过滤效果
- 过滤规则:返回所有基础字段,仅剔除所有文章层级的
text属性、所有评论层级的author属性 - 采用glob风格的路径标记作为入参,调用形式如下:
select("*,!articles.text,!articles.comments.author")
现有方案适配痛点
- 普通对象、固定深度嵌套对象的过滤逻辑,可直接通过lodash提供的
pick()、omit()方法快速实现,但一旦数据结构中存在数组嵌套,该方式就无法适配 - 调研过json-mask、node-glob、glob-object等开源工具包,均无法完全匹配上述通用性要求,通过组合这些工具的能力也无法达成目标
核心问题实现思路
通用过滤逻辑的最高效实现方式
- 先完成入参规则解析:将用户传入的选择字符串按逗号切分,拆分出白名单规则、黑名单规则两个集合,每个规则按点号拆分为路径层级,标记
*对应同层级所有属性 - 采用递归遍历方式匹配规则,无需提前感知数据结构:
- 遍历过程中遇到数组类型,就递归遍历数组内每一个元素,自动适配嵌套数组的路径层级
- 属性匹配逻辑自动忽略数组层级差异,例如规则
articles.comments.author会自动匹配「根对象 -> articles数组每个元素 -> comments数组每个元素 -> author属性」的全路径 - 规则优先级遵循:同层级精确路径优先级高于通配符路径,黑名单规则优先级高于白名单规则,匹配上黑名单的属性直接剔除
- 遍历过程中动态构造输出结果,仅保留通过规则校验的属性,避免全量拷贝原对象带来的内存开销
结合TypeScript类型系统优化类型提示的方案
- 基于模板字面量类型实现对入参选择串的静态解析,自动识别串中包含的路径结构
- 结合输入的原始数据类型做递归推导:遇到数组类型就自动将路径锚定到数组元素的类型层级,遇到
!开头的剔除规则就自动从输出类型中移除对应属性 - 最终推导得到的输出类型和实际过滤效果完全一致,无需用户手动重复定义过滤后的接口结构
内容的提问来源于stack exchange,提问作者stoniemahonie
相关产品推荐
相关产品推荐

