Hi,

Although having a valid JSON, my input never pass the validation, I have noticed the reason is the presence of justinrainbow/json-schema. I was searching the web about this and realized that it has caused some problem in other modules as well. Can you please check it out.

Many thanks,
Ramin

PS: Here is the logged error messages:

Validation errors: [{"property":"[0]","pointer":"\/0","message":"Array value found, but an object is required","constraint":"type","context":1},{"property":"[0].headers","pointer":"\/0\/headers","message":"Array value found, but an object is required","constraint":"type","context":1}]

Response failed validation: [{"action":"create","uri":"\/jsonapi\/node\/article","headers":{"Accept":"application\/vnd.api+json","Content-Type":"application\/vnd.api+json"},"requestId":"42f34c4b-9472-4414-9296-097f3dd920f4","body":"{\u0022data\u0022:{\u0022id\u0022:\u002242f34c4b-9472-4414-9296-097f3dd920f4\u0022,\u0022type\u0022:\u0022node--article\u0022,\u0022attributes\u0022:{\u0022title\u0022:\u0022this article has only a title\u0022,\u0022comment\u0022:{\u0022status\u0022:\u00220\u0022,\u0022cid\u0022:\u00220\u0022,\u0022last_comment_timestamp\u0022:\u00221525337478\u0022,\u0022last_comment_name\u0022:null,\u0022last_comment_uid\u0022:\u00221\u0022,\u0022comment_count\u0022:\u00220\u0022},\u0022metatag\u0022:[]},\u0022relationships\u0022:[]}}"}]

Comments

hedeshy created an issue. See original summary.

e0ipso’s picture

Status: Active » Postponed (maintainer needs more info)

I have never had validation errors in the past. It is possible that you have an empty array that needs to be converted to an empty object? Arrays and objects are confusing in PHP.

hedeshy’s picture

Well, I have some more info about this. It is just a warning message which makes no sense since I have checked my input with the schema provided in the module folder. So, I've just ignored it because even though this warning is logged, Subrequests and JSONAPI work the way they are supposed to and the client receives a successful response.

hedeshy’s picture

Priority: Normal » Minor
e0ipso’s picture

Title: Presence of justinrainbow/json-schema library breaks Subrequests » Warning about justinrainbow/json-schema

Thanks for taking the time to loop back on this.

skdrupal88’s picture

Priority: Minor » Normal
Status: Postponed (maintainer needs more info) » Active

I have the same problem with backend based on Contenta, the result of quick investigation:
`$input` variable in `JsonBlueprintDenormalizer.php:validateInput`method is nested array.
But validator tries to validate it with `/subrequests/schema.json`, and `schema.json` says that `subrequest` and `headers` should be objects, but these values are arrays inside $input variable.

Any request returns validation error and blocks work with the module.

Please let me know if I can provide more information.
Thanks.

ikphilip’s picture

I'm also having the same problem referenced by shorzh#6. There's no warning because JsonBlueprintDenormalizer->doValidateInput() is throwing a PHP exception with the current schema.json configuration.

AssertionError: A Subrequests blueprint failed validation (see the logs for details). Please report this in the issue queue on drupal.org in assert() (line 166 of modules/contrib/subrequests/src/Normalizer/JsonBlueprintDenormalizer.php).

My fix here is to update subrequest.type and headers.type to "array".

e0ipso’s picture

@ikphilip @skorzh do you have a patch to look at?

ikphilip’s picture

StatusFileSize
new658 bytes

@e0ipso Yes, see attached file.

e0ipso’s picture

Status: Active » Closed (works as designed)

Hmmm. It seems that the example in the project page shows this:

…
"headers": {
      "Accept": "application/vnd.api+json",
      "Content-Type": "application/vnd.api+json",
      "Authorization": "Basic YWRtaW46YWRtaW4="
    }
…

Moreover, the code that uses that input (Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer::55) says

    foreach ($data->headers as $name => $value) {
      …
    }

So it really looks like the headers property is a key-value object.

Can you validate this? (feel free to re-open).

ikphilip’s picture

Status: Closed (works as designed) » Active
StatusFileSize
new92.95 KB
new92.55 KB

I can confirm that my (sub)request header structure and body is correctly formatted. Authorization removed for simplicity.

> POST /subrequests HTTP/1.1
> Host: localhost
> Accept: application/vnd.api+json
> Content-Type: application/vnd.api+json
> Content-Length: 453
| [
| 	{ "requestId": "req-0",
|     "uri":
|      "/jsonapi/node/page?page[limit]=1",
|     "action": "view",
|     "headers":
|      { "Accept": "application/vnd.api+json",
|        "Content-Type": "application/vnd.api+json"
| 		 }
| 	},
| 	{ "requestId": "req-1",
|     "uri":
|      "/jsonapi/node/page?page[limit]=1&page[offset]=1",
|     "action": "view",
|     "headers":
|      { "Accept": "application/vnd.api+json",
|        "Content-Type": "application/vnd.api+json"
| 		 }
| 	}
| ]

When I analyze the data which passes through the deserializer the structure of the JSON is already converted to a PHP. That is, the $data object passed into Drupal\subrequests\Normalizer\JsonBlueprintDenormalizer::doValidateInput() is a PHP array.

See my debug screen shot of the $data object passed into doValidateInput().

Debug Screen of doValidateInput

The following error appears when headers.type = "object" or subrequest.type = "object". You can see from my trace that they are treated as arrays in PHP.

Regarding Drupal\subrequests\Normalizer\JsonSubrequestDenormalizer::55, by the time that code is executed $data has been transformed into a Drupal\subrequests\Subrequest object and is no longer simply a PHP array. See my SS that traces that code location.

Debug screen of denormalize

e0ipso’s picture

It looks like that the problem is on calling doValidate in the wrong place, the problem doesn't seem to be the JSON Schema, does it?

Do you think you can work in a patch in that direction? Many thanks in advance!

ikphilip’s picture

Status: Active » Closed (cannot reproduce)

I would like to work on this and I installed new Drupal and subrequests module and the problem did not reoccur. I'm going to chase down this problem as it might be a product of our app's composer dependencies. I will return this issue to Closed (cannot reproduce) since I can't replicate it.

paulmckibben’s picture

Status: Closed (cannot reproduce) » Active

I am seeing this problem in Drupal 8.7.7 and subrequests 8.x-2.2. I will try to figure out more.

paulmckibben’s picture

StatusFileSize
new626 bytes

Overall, I'm stumped on how best to fix this, especially not being familiar with the codebase.

@e0ipso, you had suggested that the call doValidateInput()needs to be moved, but I'm not sure to where, or if that would even help.

What I am seeing:

  • In BlueprintManager.php, line 35, the $request gets deserialized. Under the hood, this appears to use Symfony's JSON decoder, which decodes everything using associative arrays.
  • In JsonBlueprintDenormalizer.php, in the denormalize() function, at line 73, $this->doValidateInput($data) fails because of the way the request was deserialized in the step above.
  • Why this worked before but not now is anybody's guess. My one idea is that in a composer update, something changed about Symfony's JSON decoder, but I can't be sure about that.

For now, I'm providing this patch which just eliminates the call to doValidate(). It's a workaround, not a fix, to keep my project going, and to help anyone else running into the same thing.

I'm happy to work with others to find a more appropriate fix.

Thanks!
Paul

briangonzalezmia’s picture

I'm also experiencing the same validation failure issue as the others (Drupal core 8.7.8, and Subrequests 8.x-2.2) and can confirm that the patch in #9 and #15 both work, although I opted #9 as it it still maintains some functional validation. Thank you all!!

ikphilip’s picture

Status: Active » Needs review
StatusFileSize
new2.58 KB

I agree with paulmckibben's summary of the issue. I dug a little bit and found that the current schema works with Drupal 8.6.x but these problems begin with 8.7.x so there is probably a change in the Serialization between these versions.

I think this should testable. There's no reason we can't feed the validation function schema that we know is valid and invalid. Please consider this patch a step towards testing the updated schema.

bjcooper’s picture

Version: 8.x-2.x-dev » 3.x-dev

I've seen two separate issues that manifest with "failed validation" warnings (not sure which the OP is referring to).

The first is where subrequest blueprints fail validation. Lots of people talked about this above (and in this issue also). The patch in #9 fixed that for us.

The second issue is where the final, actual response from the Subrequests module (containing the results of all the subrequests) fails validation. For me, this is accompanied in the logs with an "assert(): A JSON:API response failed validation" warning. This only happens when you (1) have the JSON:API module enabled, (2) set the response format to JSON in the original request like so: "/subrequests?_format=json", and (3) all subrequest blueprints have "Accept: application/vnd.api+json" headers (like if all your subrequests are to JSON:API resources).

In this case, the normalize() function in subrequests/src/Normalizer/MultiresponseJsonNormalizer.php kicks in and sets the response header "Content-Type: application/json; type=application/vnd.api+json" (the "type=application/vnd.api+json" bit is sniffed from the subrequest content types).

Meanwhile, the JSON:API module is subscribed to HTTP Response events (jsonapi/src/EventSubscriber/ResourceResponseValidator.php) and processes the response before it goes out. You can see in its onResponse() method that it simply checks to see if the Content-Type of the response contains the string "application/vnd.api+json". If so, it runs the response through the JSON:API response validation. Since the Subrequests module response is not itself a valid JSON:API response (it's just JSON), it fails validation.

You can get around this in two ways. First, you could patch JSON:API module (core) to be smarter about how it checks to see if responses are JSON:API results (technically the Subrequests module isn't saying it's response Content-Type is a JSON:API result, it just contains that special string in a non-standard "type" attribute). Second, you could patch Subrequests to skip including the non-standard "type" attribute that is confusing the JSON:API module. We'll post a patch for that below.

Edit: Patch in #19.

nrogers’s picture

StatusFileSize
new842 bytes

Here's the patch mentioned in #18.

paul121’s picture

StatusFileSize
new1 KB

I was able to fix the errors by specifying Constraint::CHECK_MODE_TYPE_CAST as the validator check mode as documented in justinrainbow/json-schema here: https://github.com/justinrainbow/json-schema#configuration-options

It's description is to "Enable fuzzy type checking for associative arrays and objects" which I think makes sense in this case. One thing I noticed, that I'm not sure has been pointed out above, is that the SubrequestsTree class extends the PHP ArrayObject class. This might explain where the validator is trying to enforce arrays, not objects?

For what it's worth, I tested the next check mode on the list CHECK_MODE_COERCE_TYPES, described as "Convert data types to match the schema where possible", and it did not work. I thought it would work, but was afraid it would be too heavy-handed.

This seems like a better solution than changing the schema type to be an "array", since that really should be an "object" in order for the other JSONAPI Schema "properties", "required", etc to work. I'm not sure we need this included in test coverage, but perhaps something like the test in #17 could be added.

I do not think this fixes what @bjcooper described in #18 which seems like a separate issue. Still going to mark this for review because it would be nice to get this fixed.

paul121’s picture

I think I'm seeing the same behavior as @bjcooper in #18. The watchdog message I have is "Response failed validation. Response: {...the subrequest response}" (different than they reported, but seems similar?). The patch in #19 fixes the issue.

symbioquine’s picture

StatusFileSize
new712.49 KB

Without any patches but with the ?_format=json parameter I was getting warnings about the response validation failing because the request id keys weren't among the expected set of keys for a JSON:API response. (See my attached screenshot.)

The patch from comment #19 fixes those warnings in my case. Any chance it can be merged some time soon?

  • e0ipso committed 779d0aa on 3.x authored by paul121
    Issue #2971295 by ikphilip, paulmckibben, paul121, nrogers, Symbioquine...
  • e0ipso committed e370675 on 3.x authored by nrogers
    Issue #2971295 by ikphilip, paulmckibben, paul121, nrogers, Symbioquine...
e0ipso’s picture

Status: Needs review » Fixed

I merged #20 and a modified version of #19. This also corrects some incorrect behavior from a previous fix.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.