Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Add useful properties to error object #80

Open
jstoiko opened this issue Sep 27, 2016 · 4 comments
Open

Add useful properties to error object #80

jstoiko opened this issue Sep 27, 2016 · 4 comments

Comments

@jstoiko
Copy link
Contributor

jstoiko commented Sep 27, 2016

It would be nice if the error object (i.e. Status) returned:

  • the property on which the error occurred. currently it is not consistent, sometimes it's error.source.name, sometimes it's error.vp.name [1]
  • the constrain key that triggered the error. e.g. type, required, pattern, minLength, etc
  • the constrain value, e.g. string, true, [a-z]+, 1, etc

[1] if the property is not available (i.e. single type), maybe it could be the name of the variable that was assigned to the type, e.g. personType in the 1st example

@ddenisenko
Copy link
Contributor

ddenisenko commented Oct 5, 2016

the property on which the error occurred. currently it is not consistent, sometimes it's error.source.name, sometimes it's error.vp.name [1]

There is no such thing as "the property on which error occurred". Sometimes the error is not caused by any particular property, any particular facet etc.
The closest thing to what you want is the validation path - the mechanism designed to highlight the error source.

Let me provide an example of how to use this mechanism:

Here we define an invalid type:

var personType = ts.loadType( {
    type:"object",
    properties:{
        test : {
            type: "string[]",
            minItems:"blah"
        }
    }
})

Now lets try to find out the source(s) of the error:

var validationResult = personType.validateType();
if (!validationResult.isOk()) {
    validationResult.getErrors().forEach(function(error){
        console.log("Error [" + error.getMessage()
            + "] occurred at path ["
            + error.getValidationPathAsString() +"]")
    })
}

Here is the output:

Error ['minItems' value should be a number] occurred at path [test/minItems]

Here test/minItems is a path inside the type you validate pointing to the source.
Please note that the path can be unavailable in some cases, the type itself should be reported when this happens.

Note: you can use getValidationPath method to get the segments chain instead of the string

the constrain key that triggered the error. e.g. type, required, pattern, minLength, etc

It is recommended to use validation path, but if you wish to see the constraint and the error is caused by a constraint, you can obtain it as a source. For the example above:

var validationResult = personType.validateType();
if (!validationResult.isOk()) {
    validationResult.getErrors().forEach(function(error){
        console.log("Error [" + error.getMessage()
            + "] occurred at path ["
            + error.getValidationPathAsString() +"]")

        var errorSource = error.getSource();
        if (errorSource.facetName) {
            console.log("Facet name: " + errorSource.facetName())
        }
    })
}

Output:

Error ['minItems' value should be a number] occurred at path [test/minItems]
Facet name: minItems

the constrain value, e.g. string, true, [a-z]+, 1, etc

Same as above, it can happen that there is no facet involved, but if there is one you can obtain the value:

var validationResult = personType.validateType();
if (!validationResult.isOk()) {
    validationResult.getErrors().forEach(function(error){
        console.log("Error [" + error.getMessage()
            + "] occurred at path ["
            + error.getValidationPathAsString() +"]")

        var errorSource = error.getSource();
        if (errorSource.facetName) {
            console.log("Facet name: " + errorSource.facetName())
            console.log("Facet value: " + errorSource.value())
        }
    })
}

Output:

Error ['minItems' value should be a number] occurred at path [test/minItems]
Facet name: minItems
Facet value: blah

In case of the { type: [ 'string', 'integer' ] } illegal type there is no facet directly responsible for the error, so you will get no validation path and should report the type itself.
If you are really interested in the cause in this particular case, you can analyze the status being instance of RestrictionConflict, and get its error.getConflicting() restriction that conflicts with the other stack error.getStack().

[1] if the property is not available (i.e. single type), maybe it could be the name of the variable that was assigned to the type, e.g. personType in the 1st example

Copy-pasting the linked sample here to make it more clear:

import ts = require("raml-typesystem")

var personType = ts.loadType( {
    type: "string[]",
    minItems:3,
    maxItems:2
})

var isValid = personType.validateType();

In this example,

{
    type: "string[]",
    minItems:3,
    maxItems:2
}

is an initial type description, it could be RAML code instead.

The value of personType variable is an instance of an object, which is created by raml-typesystem library.

personType itself is a variable, you as a user created, it is totally unrelated to the raml-typesystem library, and in most languages the library would be having no access to this variable. So no, putting the name of the external user-created variable into the status being created by the library should not happen.

@jstoiko
Copy link
Contributor Author

jstoiko commented Oct 7, 2016

thanks for the pointers. your solution works fine for validation errors like pattern, maximum, minimum, however the results are not consistent for errors related to types.

For example:

  • if I pass a string to a type: 'integer', errorSource.facetName() returns should be integer and errorSource.value() returns true, I would expect to get type and integer respectively
  • if I pass a string to a type: 'number', errorSource.facetName() returns typeOf, I would expect it to return type
  • if I pass an integer to a type: 'string', errorSource.facetName() returns typeOf, I would expect it to return type
  • if I pass a string to a type: 'boolean', errorSource.facetName() returns typeOf, I would expect it to return type
  • if I pass a string to a type: 'unknown', errorSource.facetName() returns nothing and errorSource.value() returns !!!, I would expect to get type and unknown respectively
  • if I pass a number to a type: 'string | integer', errorSource.facetName() returns typeOf and errorSource.value() returns string, I would expect to get type and integer respectively

@jstoiko
Copy link
Contributor Author

jstoiko commented Oct 8, 2016

another slightly different one with dates:

  • if I pass a Sun, 28 Feb 2016 16:41:41 GMT to a type: 'date time', errorSource.facetName() returns should be datetime-only and errorSource.value() returns true, I expect -> type and datetime, not datetime-only which is the inputed type

@ddenisenko
Copy link
Contributor

@jstoiko facetName() and value() methods has meaning for the subclasses of FacetRestriction class. There is a big hierarchy of restrictions, and facet restrictions are only a part of it.

You can analyze and support the whole hierarchy if you want, but there is like 30 classes in there, and there are other sources, not only restrictions.

As I said, please use the error message and validation path to find out the source. If there is no path, report the issue to the current root.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants