使用AJV针对JSON模式验证API响应

时间:2018-10-03 03:35:54

标签: javascript rest jsonschema web-api-testing ajv

我花了很多时间阅读大量内容并对此进行了一些测试,而没有得到预期的结果。 我需要使用其JSON模式(Swagger 2.0)验证API响应。 JSON更长,但我将其简化为简单。我需要知道响应中的“ code”和“ message”关键字是否具有定义的类型和值。这是我正在使用的代码:

var Ajv = require('ajv');
var ajv = new Ajv();

var schema = {
  "host": "cert",
  "paths": {
    "products": {
      "get": {
        "responses": {
          "401": {
            "description": "Problem with the client request",
            "headers": {
              "x-correlator": {
                "type": "string",
                "format": "uuid",
                "description": "Correlation id"
              }
            },
            "schema": {
              "$ref": "file:///../errors.json#/definitions/Unauthenticated"
            }
          }
        }
      }
    },
    "products": {
      "get": {
        "responses": {
          "401": {
            "description": "Problem with the client request",
            "headers": {
              "x-correlator": {
                "type": "string",
                "format": "uuid",
                "description": "Correlation id"
              }
            },
            "schema": {
              "$ref": "file:///../errors.json#/definitions/Unauthenticated"
            },
            "examples": {
              "application/json": {
                "code": "UNAUTHENTICATED",
                "message": "Authentication error"
              }
            }
          }
        }
      }
    }
  }
}

var errors_schema = {
  "info": {
    "description": "Common errors",
    "version": "3.0.1",
    "title": "Common errors",
    "contact": {
      "name": "Team"
    }
  },
  "definitions": {
    "ModelError": {
      "type": "object",
      "required": [
        "message"
      ],
      "properties": {
        "message": {
          "type": "string",
          "description": "A human readable description"
        }
      }
    },
    "Unauthenticated": {
      "allOf": [
        {
          "type": "object",
          "required": [
            "code"
          ],
          "properties": {
            "code": {
              "type": "string",
              "enum": [
                "UNAUTHENTICATED"
              ],
              "default": "UNAUTHENTICATED",
              "description": "Request not authenticated due to missing, invalid, or expired credentials."
            }
          }
        },
        {
          "$ref": "#/definitions/ModelError"
        }
      ]
    }
  }
}

ajv.addSchema(errors_schema, 'file:///../errors.json');
var testajv = ajv.compile(schema);

var response = {"code": 123, "message":"token expired"}

var valid = testajv(response);

console.log(valid);

if(!valid) {
    console.log(testajv.errors);
}

如您所见,响应中的关键字“ code”为“ 123”整数,但在架构中将其定义为字符串。验证与值无关,始终为“ true”。我该怎么做才能满足我的需求?预先感谢。

2 个答案:

答案 0 :(得分:1)

Swagger模式包含以API结构组织的多个JSON模式,您需要解决Swagger模式的正确部分,才能使用JSON模式进行验证。

请检查示例代码(https://runkit.com/embed/bwj42juwyjo4):

var Ajv = require('ajv');
var ajv = new Ajv();

var schema = {
  "host": "cert",
  "paths": {
    "products": {
      "get": {
        "responses": {
          "401": {
            "description": "Problem with the client request",
            "headers": {
              "x-correlator": {
                "type": "string",
                "format": "uuid",
                "description": "Correlation id"
              }
            },
            "schema": {
              "$ref": "errors.json#/definitions/Unauthenticated"
            }
          }
        }
      }
    },
    "products": {
      "get": {
        "responses": {
          "401": {
            "description": "Problem with the client request",
            "headers": {
              "x-correlator": {
                "type": "string",
                "format": "uuid",
                "description": "Correlation id"
              }
            },
            "schema": {
              "$ref": "errors.json#/definitions/Unauthenticated"
            },
            "examples": {
              "application/json": {
                "code": "UNAUTHENTICATED",
                "message": "Authentication error"
              }
            }
          }
        }
      }
    }
  }
}

var errors_schema = {
  "info": {
    "description": "Common errors",
    "version": "3.0.1",
    "title": "Common errors",
    "contact": {
      "name": "Team"
    }
  },
  "definitions": {
    "ModelError": {
      "type": "object",
      "required": [
        "message"
      ],
      "properties": {
        "message": {
          "type": "string",
          "description": "A human readable description"
        }
      }
    },
    "Unauthenticated": {
      "allOf": [
        {
          "type": "object",
          "required": [
            "code"
          ],
          "properties": {
            "code": {
              "type": "string",
              "enum": [
                "UNAUTHENTICATED"
              ],
              "default": "UNAUTHENTICATED",
              "description": "Request not authenticated due to missing, invalid, or expired credentials."
            }
          }
        },
        {
          "$ref": "#/definitions/ModelError"
        }
      ]
    }
  }
}

ajv.addSchema(errors_schema, 'errors.json');
ajv.addSchema(schema, 'swagger.json')



var testajv = ajv.compile({ $ref: 'errors.json#/definitions/Unauthenticated' });

console.log(testajv({"code": 123, "message":"token expired"}), testajv.errors); // Fails

console.log(testajv({"code": "AAA", "message":"token expired"}), testajv.errors); // Fails

console.log(testajv({"code": "UNAUTHENTICATED", "message":"token expired"}), testajv.errors); // Passes

var testajv2 = ajv.compile({ $ref: 'swagger.json#/paths/products/get/responses/401/schema' });

console.log(testajv2({"code": 123, "message":"token expired"}), testajv2.errors); // Fails

console.log(testajv2({"code": "AAA", "message":"token expired"}), testajv2.errors); // Fails

console.log(testajv2({"code": "UNAUTHENTICATED", "message":"token expired"}), testajv2.errors); // Passes

ajv相关的问题中的更多信息:https://github.com/epoberezkin/ajv/issues/195

答案 1 :(得分:0)

在代码属性中使用类型作为数字而不是字符串。

"properties": {
        "code": {
          "type": "number",
          "enum": [
            "UNAUTHENTICATED"
          ],
          "default": "UNAUTHENTICATED",
          "description": "Request not authenticated due to missing, invalid, or expired credentials."
        }
      }