Comments (7)
However, this introduces indeterminate return types for get_media() based on whatever the custom Handler may be doing, which arguably is even less desirable than needing to rely on a Middleware-defined property.
I don't think this is a particular issue, since the multipart handler does returns a custom object https://falcon.readthedocs.io/en/stable/api/multipart.html
As media is cached upon first access, another middleware component that runs earlier might even bypass validation if we added kwargs that control representation per the above suggestion.
this is the biggest problem I see of such a solution.
I considered allowing get_media() to pass arbitrary keyword-arguments through to the handler (which would allow something like
req.get_media(type=schema_class)
within the view logic itself to pass a msgspec schema straight through to a custom Handler class)
I think if we were to go with this system then we get_media should have a kwarg that's passed as kwarg to the handler. so this example would be something like req.get_media(handler_kwargs=dict(type=schema_class))
from falcon.
Thanks for the discussion on Gitter, and taking time to write down a very nice summary here!
I don't know what the best way is either, but I agree it would be nice to streamline this scenario.
Adding kwargs to req.get_media()
might be problematic since the current kwargs do not alter the way media is deserialized as they only control the behaviour wrt missing media, i.e., the caller can implement the same effect by catching exceptions without having any other prior knowledge.
As media is cached upon first access, another middleware component that runs earlier might even bypass validation if we added kwargs that control representation per the above suggestion.
from falcon.
@CaselIT how would kwargs help in the case of cached media? Or would we buffer the stream somehow, and invalidate upon different kwargs?
from falcon.
They would be used only when first calling get_media.
I don't think it's a good change to replace caching that we have in place
from falcon.
Honestly it would not make for a great api since this would be allowed
a_foo = req.get_media(handler_kwargs=dict(type=Foo))
user_wants_a_bar_but_gets_a_foo = req.get_media(handler_kwargs=dict(type=Bar))
Of course this is an edge case that's unlikely to be realistic, but it's still not great.
I honestly don't know how to make it better
from falcon.
Agreed, I don't think it is easy to incorporate this into the current API.
We could make broader changes to the framework to afford this scenario, but that of course requires more thought. Options include:
- Add a new
schema
(orvalidator
or similar) kwarg to the deserialization interface, that the framework would pass itself. It could be optionally set byadd_route()
(like suffix), or maybe even automagically by attaching an OAS schema to the App? (The latter sounds too complex, maybe better suited for an add-on?) We only support decorator-basedjsonschema
validation atm, but we could think of a centralized approach too, like middleware vs hooks (current validation is like hooks). - Variations of the above, the generalized idea is to pass more contextual information from
req
than justcontent_type
andcontent_length
. - Change how caching works, and allow repeated deserialization with different params. This is probably not a very bright idea, since one might end up caching similar data twice, as seen in some other framework. Also breaks Falcon's philosophy that no buffering is performed behind the user's back.
- What else?
from falcon.
What else?
I don't know if this makes much sense, but one option that comes to mind is that instead of having get_media()
pass kwargs through in some way, there could be some officially-sanctioned method for setting the media
cache explicitly in the instance that multiple layers might be trying to access the stream/get_media. Not sure of the performance implications, but you might have a signature like:
def set_media_cache(cached: Union[dict, Object, Callable])
If you pass in a dict or other object, it just gets assigned to the media cache, and returned next time anything calls get_media()
. If you pass in a callable, it gets executed (and the results stored in the cache) the next time get_media()
is called.
So my middleware that wants to validate the stream might do something like:
try:
validated_media = msgspec.json.decode(req.stream.read(), type=schema)
req.set_media_cache(partial(msgspec.structs.todict, validated_media)
except WhateverGetsThrownWhenStreamIsAlreadyConsumed:
validated_media = msgspec.convert(req.get_media(), type=schema)
req.context.validated_media = validated_media
from falcon.
Related Issues (20)
- `DefaultEventLoopPolicy.get_event_loop()` is deprecated (in the case of no loop) HOT 3
- Make contributor's checklist pass on CPython 3.12
- unable to iterate through `MultipartForm` multiple times HOT 2
- `http_date_to_dt()` should return a timezone-aware datetime
- Drop `--no-build-isolation` in testing
- IPv6 WSGI server fails to start
- Migrate to "pure Python" Cython mode where applicable HOT 3
- Make Python 3.12 the default CI version
- Docs facelift HOT 2
- Refactor CONSUME_MULTIPLE_SEGMENTS in BaseConverter HOT 1
- TestClient methods are typed to return _ResultBase, but actually return Result HOT 4
- TestClient sets buffered_stream, but not stream HOT 3
- Add support for 'partitioned' attribute to set_cookie() HOT 7
- Migrate to another code formatter? HOT 5
- Make it easier to extend/subclass default router
- Document how resp is affected by raising `HTTPError`/`HTTPStatus` HOT 3
- Generalize validators to support additional types of validation other than jsonschema HOT 2
- Use `ruff` linter instead of `flake8`
- Update installation docs wrt PEP 517
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from falcon.