question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Allow a single location for each field

See original GitHub issue

See 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 to Field
  • Only accept a single location in use_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 with DEFAULT_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:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:11 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
sirosencommented, Aug 27, 2019

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.

0reactions
sirosencommented, Aug 31, 2019

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:

  • I’m marking this as v6.0.0 in the changelog and noting differences from webargs v5. Does that sound right?
    • Maybe webargs wants to do a final 5.x release before this merges, so that it can be the start of a 6.x branch with any other changes we might want
  • To try to keep things clear in meaning, I’m doing a rename 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 do
  • Going to a single DEFAULT_LOCATION = "json" and a single location per call is a big API improvement, IMO – I’ve been pursuing that.
    • "json" is arguable as a choice. But flask-rest-api defaults to json and I came across flask-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 right

I’ve been thinking about a couple of sticky cases in this thread and I have two ideas I’d like to put forth.

I’ve seen APIs that accept either form-encoded or JSON request payloads.

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:

  • try to load json, then form body, without passing the result to schema (aside: ensure that all json parse methods return missing when there’s no content, not {} – I noticed that not all do)
  • pass whatever the result of the above is – missing if neither is populated, json data if both are, form post only if json is missing and form body is present – to the schema
  • no retry, fallback, or other nesting of errors

The 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 like try_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.

Won’t we need to merge error messages for the stacked case?

@use_args({"related_id": fields.Str(required=True))}, location="query"})
@use_args({"name": fields.Str(required=True))}, location="json")
{"related_id": ['Missing...'], "name": ["Missing..."]}

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:

@webargs.collect(
    parser.use_args({"related_id": fields.Str(required=True))}, location="query"}),
    parser.use_args({"name": fields.Str(required=True))}, location="json"),
)
def viewfunc(name, related_id):
    ...

which might raise a

WebargsCollectedError([
  {"related_id": ['Missing...']},
  {"name": ["Missing..."]}
])

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 in pallets/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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Carrying Location Objects in RADIUS and Diameter RFC 5580
Carrying Location Objects in RADIUS and Diameter (RFC 5580, August 2009) ... This field MUST contain the value of exactly one IANA-registered 'method'...
Read more >
RFC 6442: Location Conveyance for the Session Initiation ...
The Geolocation header field MUST have at least one locationValue. A SIP intermediary SHOULD NOT add location to a SIP request that already...
Read more >
Language Guide (proto3) | Protocol Buffers - Google Developers
The SearchRequest message definition specifies three fields (name/value pairs), one for each piece of data that you want to include in this type...
Read more >
HTTP/1.1: Header Field Definitions
Each media-range MAY be followed by one or more accept-params, beginning with the "q" parameter for indicating a relative quality factor. The first...
Read more >
Creating RFC Destinations - Tricentis
RFC Destinations store the settings that allow LiveCompare to connect to your SAP systems. In cases where a direct connection to an SAP...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found