如何使用具有必需字段的JSON模式验证http PATCH数据



我正在尝试验证一个经典的JSON模式(使用Ajv和JSON服务器(,该模式包含必需的字段,但用于HTTP PATCH请求。

POST是可以的,因为数据是完整到达的,不应该提交任何内容。

但是,当尝试PATCH现有资源时,架构的必需字段会产生问题。

以下是我目前正在做的POST:

const schema = require('./movieSchema.json');
const validate = new Ajv().compile(schema);
// ...
movieValidation.post('/:id', function (req, res, next) {
const valid = validate(req.body);
if (!valid) {
const [err] = validate.errors;
let field = (err.keyword === 'required') ? err.params.missingProperty : err.dataPath;
return res.status(400).json({
errorMessage: `Erreur de type '${err.keyword}' sur le champs '${field}' : '${err.message}'`
});
}
next();
});

但如果我对movieValidation.patch(...)也这样做,并试图只发送以下数据块:

{
"release_date": "2020-07-15",
"categories": [
"Action",
"Aventure",
"Science-Fiction",
"Thriller"
]
}

它将使整个验证失败(而所有字段都是可以的,并且它们验证模式(

这是我完整的moviesSchema.json:

{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"title": {
"title": "Titre",
"type": "string",
"description": "Titre complet du film"
},
"release_date": {
"title": "Date de sortie",
"description": "Date de sortie du film au cinéma",
"type": "string",
"format": "date",
"example": "2019-06-28"
},
"categories": {
"title": "Catégories",
"description": "Catégories du film",
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"title": "Résumé",
"description": "Résumé du film",
"type": "string"
},
"poster": {
"title": "Affiche",
"description": "Affiche officielle du film",
"type": "string",
"pattern": "^https?://"
},
"backdrop": {
"title": "Fond",
"description": "Image de fond",
"type": "string",
"pattern": "^https?://"
}
},
"required": [
"title",
"release_date",
"categories",
"description"
],
"additionalProperties": false
}

目前,我使用了一个与原始模式相同的不同模式,但结尾没有required子句。但我不喜欢这个解决方案,因为它不必要地重复代码(而且一点也不优雅(。

有什么聪明的解决方案/工具可以正确地实现这一点吗?感谢

如果您正确使用了HTTP PATCH,那么还有另一种方法可以解决这个问题。

PATCH请求的主体应该是某种不同的媒体类型,而不是简单的JSON。diff媒体类型定义了一组操作(添加、删除、替换(来转换JSON。然后将diff应用于原始资源,从而产生资源的新状态。有两种JSONdiff媒体类型是JSONPatch(功能更强大(和JSONMergePatch(更自然(。

如果您验证PATCH的请求主体,那么您实际上并不是在验证资源,而是在验证diff格式。但是,如果您首先将补丁应用于资源,则可以使用完整的模式验证结果(然后根据结果保留更改或400(。

记住,在REST中,重要的是资源和表示,而不是请求和响应。

拥有多个模式并不罕见,每个要验证的负载都有一个模式。

在你的情况下,看起来你做了完全正确的事情。

您可以使用引用($ref(消除模式的重复,将属性子模式拆分到一个单独的文件中。

您最终得到一个包含您的模型的模式,以及所述模型的每个表示形式的模式,但没有重复(在可能的情况下(。

如果你需要更多关于如何做到这一点的指导,请发表评论,我会用更多细节更新答案。


下面是一个如何做你想做的事情的例子。您将需要创建多个模式文件,并在需要验证POST或PATCH请求时引用正确的模式。我已经简化了这些例子,只包括";标题";。

在一个模式中,您有类似于。。。

{
"$id": "https://example.com/object/movie",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"movie": {
"properties": {
"title": {
"$ref": "#/definitions/title"
}
},
"additionalProperties": false
},
"title": {
"title": "Titre",
"type": "string",
"description": "Titre complet du film"
}
}
}

然后你会有一个用于POST和PATCH。。。

{
"$id": "https://example.com/movie/patch",
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [{
"$ref": "/object/movie#/definitions/movie"
}],
}
{
"$id": "https://example.com/movie/post",
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [{
"$ref": "/object/movie#/definitions/movie"
}],
"required": ["title"]
}

example.com更改为要用于ID的任何域。然后,您需要将所有模式加载到实现中。

加载后,引用将工作,因为它们基于URI解析,对每个模式资源使用$id

请注意,POST和PATCH模式中的$ref值不是以#开头的,这意味着目标不是THIS模式资源。

最新更新