swaggest / php-json-schema

High definition PHP structures with JSON-schema based validation
MIT License
451 stars 51 forks source link

Return all errors instead of raising exception #103

Open sp-jose-herrero opened 4 years ago

sp-jose-herrero commented 4 years ago

I was trying to migrate from justinrainbow/json-schema for validation, but while with other libraries you can get a list of the not passing validations with this one you can only obtain the first one.

It will be handy to have a option to specify that you don't want to throw an exception on the first error.

skewty commented 3 years ago

The validation is not usable to our project as implemented.

Here is our use case:

We have a PayloadMap class that essentially goes through an array/map of ClassStructure classes (class Payload) one after the other trying to create the payload (no exception on import). Our Payload class has a method named "positivelyIdentified` that that helps PayloadMap determine if it should keep trying other Payload classes when exception occurs creating the payload. In order for this logic to work correctly, we need all the errors not the first encountered.

If I have, for example, a "type" field that need to have a value of "FooType" for this payload to be positively identified I might write something like:

class FooEvent extends Payload
{
    const TYPE = "FooType";

   // ... other fields
    public string $type;

    public static function setUpProperties($props, $schema)
    {
        // ...
        $props->type = Schema::string();
        $props->type->enum = [self::TYPE];
        // ...
    }

    public static function positivelyIdentified(Error $error): bool
    {
       /* Basically if the type value provided is correct the payload is positively identified 
          and the payload map should not continue to try the data against other payload classes */
        return array_search(
               "/definitions/FooEvent/properties/type", 
               $error->schemaPointers
         ) == false;
    }
}

But this code flow doesn't work if some unimportant field happens to raise the exception first.

Subset of the code talked about

const CONTENT_TYPE_JSON = "application/json";

abstract class Payload {
    use ClassStructureTrait;

    public abstract static function setUpProperties($props, Schema $schema);

    public static function parse($data, $contentType = CONTENT_TYPE_JSON) : self 
    {
       // Choose a decoding function based on contentType and then return self::import($decodedData)
    }

    public static function positivelyIdentified(Error $error): bool
    {
        return false;
    }
}

class PayloadMap {
    public function dispatch($data, string $contentType = CONTENT_TYPE_JSON, $errorHandler = null) {
        // ...
        // the key of the map is the Payload class and the value is a list of handlers / callbacks
        // ...
    }
}