Ajv: Can't resolve reference inside a schema to an external .json file on a server

Created on 11 Jul 2017  路  7Comments  路  Source: ajv-validator/ajv


I have the following problem:
I want to build an Angular 2 service that loads json schemes from a server by simple http-get calls and stores them in json objects. These objects should then be added to the ajv instance to being able to perform a validation.
My json schema api on the server side is structured in a folder with all top level json schemes and a folder next to these top level schemes, with all the referenced definitions:

What version of Ajv are you using? Does the issue happen if you use the latest version?

I use json-schema-draft-04

Ajv options object

this.ajvInstance = new Ajv( {
      meta: false,
      extendRefs: true,
      unknownFormats: 'ignore',
      allErrors: true
    });

JSON Schema

{
  "$id":          "http://url/to/folder/getPlan_V0.json",
  "title":        "getPlan_V0.0.6",
  "$schema":      "http://json-schema.org/draft-04/schema#",
  "type":         "object",
  "properties": {
    "session_id": {
      "$ref": "definitions/session_id_V0.json"
    },
    "barcode": {
      "$ref": "definitions/barcode_V0.json"
    }
  },
  "additionalProperties": false,
  "required": [ "session_id", "barcode" ]
}

The file session_id_V0.json is in a separate folder next to getPlan_V0.json:

{
  "title":        "session_id_V0.0.2",
  "$schema":      "http://json-schema.org/draft-04/schema#",
  "type":         "string",
  "minLength":    32,
  "maxLength":    32
}

Sample data


Your code
The 2 schemes are already stored as json objects in the two variables given to .addSchema

let metaSchema = require( 'ajv/lib/refs/json-schema-draft-04.json' );
    this.ajvInstance.addMetaSchema( metaSchema );
    this.ajvInstance._opts.defaultMeta = metaSchema.id;
    this.ajvInstance.addSchema( this.json_schemes.getPlan_V0, 'getPlan_V0' );
    this.ajvInstance.addSchema( this.json_schemes_definitions.session_id_V0, 'session_id_V0.json' );

let valid = this.ajvInstance.validate( schema, object_to_validate );

    if( valid ) {
      returnValue = true;
    } else {
      returnValue = false;
    }

Validation result, data AFTER validation, error messages

Error: can't resolve reference definitions/session_id_V0.json from id http://url/to/folder/getPlan_V0.json#

What results did you expect?
I expected valid to not being true, as the object_to_validate is not of the tested type.

Are you going to resolve the issue?

Most helpful comment

Thank you so far for your support!!
I now changed my code to use compileAsync with the exact same function loadSchema as provided by your example, but I get the following error

Unhandled Promise rejection: request.json is not a function ; Zone: ProxyZone ; Task: Promise.then ; Value: TypeError: request.json is not a function
    at Object.loadSchema (VM124 main.bundle.js:2741)
    at loadMissingSchema (VM123 vendor.bundle.js:688)
    at _compileAsync (VM123 vendor.bundle.js:677)
    at VM123 vendor.bundle.js:653
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (VM115 polyfills.bundle.js:2794)
    at ProxyZoneSpec.webpackJsonp.../../../../zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (VM123 vendor.bundle.js:69461)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (VM115 polyfills.bundle.js:2793)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (VM115 polyfills.bundle.js:2544)
    at VM115 polyfills.bundle.js:3221
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (VM115 polyfills.bundle.js:2827) TypeError: request.json is not a function
    at Object.loadSchema (http://localhost:9876/_karma_webpack_/main.bundle.js:2741:24)
    at loadMissingSchema (http://localhost:9876/_karma_webpack_/vendor.bundle.js:688:64)
    at _compileAsync (http://localhost:9876/_karma_webpack_/vendor.bundle.js:677:48)
    at http://localhost:9876/_karma_webpack_/vendor.bundle.js:653:34
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2794:26)
    at ProxyZoneSpec.webpackJsonp.../../../../zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/vendor.bundle.js:69461:39)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2793:32)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2544:43)
    at http://localhost:9876/_karma_webpack_/polyfills.bundle.js:3221:57
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2827:31)

Do you have any idea what that could be?

All 7 comments

Additionally, is there a way of directly importing json schemes from a server to the ajv instance?

  1. You are not using references correctly.

There are no definitions in your schema, so $ref cannot be resolved. If they are in a different file, full URI should be used with hash fragment.

  1. You can use compileAsync method - see the docs.

If you want to reference the whole file, just use its name, why do you need "definitions/"? Also the second file is not added to Ajv instance.

The second file, which I want to reference to, is in the folder definitions. That is why I have the definitions in the $ref argument. Do I have to put the whole URL to the file in the$ref argument?

_Sent from my HUAWEI MHA-L29 using FastHub_

I can't say without looking at files. You have to explicitly add all the referenced files using addSchema method and the resolved URI (using schema id as base URI - see RFC3986) should be the same as id in the added file. This is all according to JSON Schema spec. If you use the method compileAsync the schemas will be downloaded from full resolved URIs using the hook you passed via options.

Also your schema is draft-06 (you use $id) and you use $schema for draft-04, although that is not what is not working here - you simply use incorrect references (most likely :).

Thank you so far for your support!!
I now changed my code to use compileAsync with the exact same function loadSchema as provided by your example, but I get the following error

Unhandled Promise rejection: request.json is not a function ; Zone: ProxyZone ; Task: Promise.then ; Value: TypeError: request.json is not a function
    at Object.loadSchema (VM124 main.bundle.js:2741)
    at loadMissingSchema (VM123 vendor.bundle.js:688)
    at _compileAsync (VM123 vendor.bundle.js:677)
    at VM123 vendor.bundle.js:653
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (VM115 polyfills.bundle.js:2794)
    at ProxyZoneSpec.webpackJsonp.../../../../zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (VM123 vendor.bundle.js:69461)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (VM115 polyfills.bundle.js:2793)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (VM115 polyfills.bundle.js:2544)
    at VM115 polyfills.bundle.js:3221
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (VM115 polyfills.bundle.js:2827) TypeError: request.json is not a function
    at Object.loadSchema (http://localhost:9876/_karma_webpack_/main.bundle.js:2741:24)
    at loadMissingSchema (http://localhost:9876/_karma_webpack_/vendor.bundle.js:688:64)
    at _compileAsync (http://localhost:9876/_karma_webpack_/vendor.bundle.js:677:48)
    at http://localhost:9876/_karma_webpack_/vendor.bundle.js:653:34
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2794:26)
    at ProxyZoneSpec.webpackJsonp.../../../../zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/vendor.bundle.js:69461:39)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2793:32)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2544:43)
    at http://localhost:9876/_karma_webpack_/polyfills.bundle.js:3221:57
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/polyfills.bundle.js:2827:31)

Do you have any idea what that could be?

Was this page helpful?
0 / 5 - 0 ratings