问题描述
我正在尝试使用必填字段验证经典的JSON模式(带有Ajv和json-server),但用于HTTP PATCH请求。
对于POST来说是可以的,因为数据已全部到达并且不应遗漏任何内容。
但是,尝试修补现有资源时,架构的 required 字段会引起问题。
这是我目前正在做的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","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","pattern": "^https?:\/\/"
},"backdrop": {
"title": "Fond","description": "Image de fond","pattern": "^https?:\/\/"
}
},"required": [
"title","release_date","categories","description"
],"additionalProperties": false
}
现在,我使用了与原始模式相同的模式来完成技巧,但是最后没有required
子句。但是我不喜欢这种解决方案,因为它不必要地复制了代码(而且一点也不优雅)。
是否有任何聪明的解决方案/工具可以正确实现这一目标? 谢谢
解决方法
具有多个模式(要验证的每个有效负载一个)并不罕见。
根据您的情况,您似乎做对了正确的事情。
您可以使用引用($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","allOf": [{
"$ref": "/object/movie#/definitions/movie"
}],}
{
"$id": "https://example.com/movie/post","required": ["title"]
}
将example.com
更改为您要用于ID的任何域。
然后,您需要将所有模式加载到实现中。
加载后,引用将基于URI解析而起作用,并为每个架构资源使用$id
。
请注意,POST和PATCH模式中的$ref
值不是以#
开头,这意味着目标不是此模式资源。
如果正确使用HTTP PATCH,则有另一种方法可以解决此问题。
PATCH请求的主体应该是某种差异媒体类型,而不是纯JSON。 diff媒体类型定义了一组要转换JSON的操作(添加,删除,替换)。然后将差异应用于原始资源,从而导致资源处于新状态。 JSON Patch(更强大)和JSON Merge Patch(更自然)是几种JSON diff媒体类型。
如果您验证PATCH的请求正文,则不是在验证资源,而是在验证diff格式。但是,如果您首先将补丁应用于资源,则可以使用完整架构验证结果(然后根据结果保留更改或保留400)。
请记住,在REST中,重要的是资源和表示形式,而不是请求和响应。