Closed (fixed)
Project:
JSON:API
Version:
8.x-2.x-dev
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
5 Jun 2018 at 18:29 UTC
Updated:
28 Aug 2018 at 18:14 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
gabesullicegabesullice created an issue.
IOW, I think there's still room for improvement on this topic.
Comment #2
wim leersWow. Such a great find! And so painfully obvious now 😳
I propose that in the 2.x branch of JSON API, we simply forbid
?_format=api_json. Using it will result in a 400 response.That's what http://jsonapi.org/format/#query-parameters requires. And in practice, most people using JSON API probably are already omitting it anyway.
Implementing this will be easy after #2933062: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters lands, since #2933062-25: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters added a
@todoreferring to this issue; we'll just need to delete that@todoand the line below it!Comment #3
gabesulliceYes, please. 😍🙏+💯
Comment #4
wim leers👌
Comment #5
gabesulliceI just committed #2933062: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters.
Doing this one after lunch!
Comment #6
gabesulliceErr, there's not a patch. Don't know why this was RTBC lol.
Comment #7
gabesulliceI'm just going to make the call and commit this if tests pass. That's what major version number bumps are for, right?
Comment #8
wim leersLOL! 😅
Comment #9
gabesulliceWow, so this has a super obscure interaction with #2948666: Remove JSON API's use of $context['cacheable_metadata'].
Surprisingly, we can't actually return a
JsonApiTopLevelDocumentwith anerrorsobject; only one withdata.Right now, all error responses arise from thrown exceptions. So why not just throw an exception? Well, we can't actually throw an exception that results in an equivalent error object because we don't have an exception type that can carry customized links (!). The customized link the currrent patch has is:
http://jsonapi.org/format/#query-parameters.JsonApiDocumentTopLeveleven has the following class comment:Sooo, I'm not too pleased with how this interdiff looks. Not sure if we want to fix it like this for now and just have follow up to do it "right" later or if we want to make it easy to do "right" first.
Comment #10
wim leersRe-applied #9's interdiff on top of #7.
Comment #12
e0ipsoAre we forbidding any parameter unmanaged by the spec? Or are we targeting only _format?
There are many reasons to need arbitrary qs params. I want to make sure that is still a possibility.
Comment #13
wim leersWasn't sure about this either, but I think I managed to find another solution without spending a lot of time on it. It:
\Drupal\jsonapi\EventSubscriber\JsonApiRequestValidator::validateQueryParams()to not return aResourceResponse(this was the only place creating aResourceResponsewitharrayas its data, probably wrongly so — my bad!), and instead return a HTTP exception.\Drupal\jsonapi\EventSubscriber\DefaultExceptionSubscriber::onException(), so we're basically done! There is only one caveat: that means we lose theerrors.links.info = http://jsonapi.org/format/#query-parameterspiece of information. But even that can be solved pretty elegantly.This is even a net code reduction, and frankly is how
JsonApiRequestValidator.phpshould've worked in the first place. It was only added yesterday (in #2933062: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters). So it's definitely fine to refine it.Comment #14
wim leers#12: See #2933062: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters!
Comment #16
e0ipsoI saw that and realized that it was forbidding all qs params. That's unfortunate. I'd like to review that.
Comment #17
wim leersD'oh #13 should have been posted on #2982478: JsonApiRequestValidator creates ResourceResponse object with array instead of JsonApiDocumentTopLevelNormalizerValue 😅 Did that, and got it committed. HEAD is now passing tests again!
Comment #18
wim leersIt doesn't! It forbids all query string parameters that the JSON API spec reserves. Something like
foo=baris forbidden, but something likefoo_foo=baris allowed. This is just the JSON API spec, nothing more or less. See http://jsonapi.org/format/#query-parametersAccording to those rules,
_format=api_jsonis also forbidden. But since likely many clients are usingURL?_format=api_json, that parameter was special-cased to be allowed by #2933062: [>=8.5.4] Spec Compliance: Return 400 for unrecognized/unsupported query parameters. This issue aims to change that, for better spec compliance.Comment #19
wim leersRe-testing #7, which should still apply cleanly, and now should no longer be affected by failing HEAD tests.
Comment #20
gabesulliceMost of the changes from #13 have already been integrated in #2982478: JsonApiRequestValidator creates ResourceResponse object with array instead of JsonApiDocumentTopLevelNormalizerValue.
That leaves the original changes. IMHO, I think this can be committed as is.
There's a related followup that deals with the larger topic in #16 here: #2984044: Ignore some query parameters which violate the JSON API specification.
Comment #21
gabesulliceD'oh! Patch attached.
Comment #22
wim leersIf we commit this, then accessing
/jsonapi/node/articlevia a browser will result in Dynamic Page Cache entries that are have thehtmlrather thanapi_jsonformat. This is because of the logic inFormatSetteronly automatically setting theapi_jsonformat only if the correctAcceptheader is specified.I think we want to change that, so that the
api_jsonformat is always set for every JSON API route?This may seem out of scope here, but the change here is effectively forbidding the use of
/jsonapi/node/article?_format=api_json, and hence this issue is forcing the need for that change.Comment #23
gabesulliceAre you sure?
That's already how it works.
FormatSettercalls$this->isJsonApiRoute()which is:So any matched JSON API route already works like you said. It's just when the route isn't matched and there is no
Acceptheader that it "fails". In that case, it will send an HTML 404. When is a route not matched? When a resource UUID doesn't exist or a URL has a typo in it.I think I'm fine with that for the browser. I could be convinced otherwise.
Comment #25
gabesulliceThis was kicked back because HEAD broke on the latest version of core.
Comment #26
wim leersI should have been more specific. This is what I meant:
(That's with only those 2 requests in the browsers on the right hand side having occurred.)
Comment #27
wim leersActually, this is already the case in HEAD. I should've just opened a separate issue for that. Did that now: #2987205: FormatSetter doesn't set the format to `api_json` when accessing just `/jsonapi`.
Sorry for distracting this issue.
IMHO that leaves one thing left to do: ensure that the upgrade DX is good.
Is not very helpful for those that were doing it before. Let's be more helpful.
That's nicer, isn't it?
Comment #29
wim leersI'm sure some would argue "why even bother restricting this if we can just whitelist this one parameter and not annoy anybody with it?". I understand that.
?_formatgot so much hate after Drupal 8 was released. So much. I'd need all my fingers and toes multiple times to count the number of times I've had to link to this CR: https://www.drupal.org/node/2501221. Many comments on that CR too, all complaining.The reasons for having to use
?_formatdon't affect JSON API, thanks to it being served from its own routes, and hence there not being any need for content negotiationBut if tutorials/documentation keeps referring to
?_format, then that keeps harming us/Drupal.Comment #30
wim leersComment #31
gabesulliceLet's make a followup so that this link is not under the `info` key.
Comment #32
wim leersComment #33
gabesulliceThis has been RTBC for a couple weeks, I think we're waiting for @e0ipso to commit it?
Comment #34
wim leersCorrect!
Comment #35
e0ipsoI'm not sure about this point. I think the Drupal hate comes from somewhere else, but I'll concede to
Merging.
Comment #36
e0ipsoI got merge conflicts. Sending a new re-rolled patch.
#2949807: Spec Compliance: Error responses are missing the `jsonapi` top-level member
Comment #38
gabesulliceCommitted because this was RTBC before and blocked on @e0ipso. In #35 @e0ipso attempted to merge that patch but got a merge conflict. Now, this LGTM and we can get this in!
Comment #39
gabesulliceComment #40
wim leers🍻