RFC: Allow a single location for each field
See original GitHub issueSee discussion in https://github.com/marshmallow-code/webargs/issues/267.
The idea is that the Schema would be passed the whole data from a location, so there couldn’t be fields with different location in the same Schema.
- Drop
location
argument toField
- Only accept a single
location
inuse_args
This is an important breaking change.
It breaks the default use case, which is to iterate on all fields, and for each field search in DEFAULT_LOCATIONS
(by default: query string, form, then json).
We could keep a somewhat similar behaviour by trying to load the whole data from query string, then form, then json. The only added restriction is that Schema couldn’t contain fields from mixed locations.
I’m not convinced with the multi-location feature, so we could even
- Replace
DEFAULT_LOCATIONS
withDEFAULT_LOCATION
The user could subclass the parser to change the default location (in our framework, we use json by default), and he would need to specify the location explicitly when it is not the default.
I think all this changes allow for better documentation (e.g. in apispec).
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:11 (8 by maintainers)
Top GitHub Comments
I’m definitely willing to, but I’m not sure when I’ll get to it. I can try to carve out time for it in the next 2 weeks.
I’ve finally got a few hours today to try to get something real going. This branch in my fork is where I’ll be hacking away if anyone wants to take a peek, but this is just what I could scratch together during the work-week and it’s quite broken right now (almost all tests fail).
Initial thoughts and questions based on starting on an implementation:
parse_{location}
->location_load_{location}
, e.g.location_load_json
. I’m going with this somewhat verbose option in the hopes that it’s clear that this is just a hook for reading data but doesn’t do any “parsing”Parser.parse_arg
is going away because it’s not clear what it should doDEFAULT_LOCATION = "json"
and a singlelocation
per call is a big API improvement, IMO – I’ve been pursuing that."json"
is arguable as a choice. Butflask-rest-api
defaults tojson
and I came acrossflask-restful
as well, which uses('json', 'values')
.get_value
is being replaced with a schema-aware proxy for result dicts – otherwise, MultiDicts won’t work rightI’ve been thinking about a couple of sticky cases in this thread and I have two ideas I’d like to put forth.
This seems very legitimate and should be supported out-of-the-box if possible. Is this the only “normal” case we’re aware of in which a single schema is applied to multiple locations?
If so, I’d suggest adding
location="json_or_form"
with the following meaning:missing
when there’s no content, not{}
– I noticed that not all do)missing
if neither is populated, json data if both are, form post only if json is missing and form body is present – to the schemaThe result would be write-able in terms of a
location_load_json_or_form
method on the base parser, I think.I like this because it doesn’t (re)introduce
locations=...
or a rename liketry_locations=...
just to handle a special case that we want to support.If users have more exotic APIs – e.g. “takes query parameters or headers for X” – they can implement it following this same model on a custom
Parser
subclass. They can even implement strange (read: unwise) things like merging locations with this kind of “meta-location” pattern.In exchange for putting a slight burden on users in this case, I think we can support this really easily with this kind of usage:
which might raise a
The result will be that
use_args
stays very simple and easy to maintain.If we want
use_args
to do this internally, I think it’s still a good idea to keep the errors separate, wrapped in a list, and not try to merge their contents together. The user can decide what to do with that information.The best way I can think to support this “magically” (i.e. without the explicit
collect
wrapper) is the approach used inpallets/click
in which you create a special attribute to store data. You then need to replace the function with a singular callable (click uses objects, but maybe just a function is fine) that knows how to handle that attribute – so it’s slightly tricker than the typical nested decorators case.