Comments (5)
I'm having trouble understanding warp's filter model; possibly my context_extractor
is supposed to do something special to say that its error is terminal? but make_graphql_filter
's behavior seems suboptimal at least:
- it's not great to call
context_extractor
twice at least from a efficiency/load perspective, and - it's not great to try parsing an
application/json
body as graphql, and then to report that error instead of the one from the firstcontext_extractor
call
from juniper.
I personally haven't used warp so I will let other maintainers or community members chime in on this.
from juniper.
@scottlamb sorry for responding late on this.
but
make_graphql_filter
's behavior seems suboptimal at least:
- it's not great to call
context_extractor
twice at least from a efficiency/load perspective, and- it's not great to try parsing an
application/json
body as graphql, and then to report that error instead of the one from the firstcontext_extractor
call
This behavior is definitely wrong. Especially, considering possible non-idempotent mutation semantics.
It seems that we're missing reject
in our .or()
filter chains, so failing one branch switches to another one without rejection as desired.
from juniper.
@scottlamb upon further investigation, it seems that everything is relatively fine in juniper_warp
, but a big misunderstanding of warp
filters has place. See seanmonstar/warp#388 (comment) for the main insight:
Rejections are meant to say a
Filter
couldn't fulfill its preconditions, but maybe anotherFilter
can. If a filter is otherwise fully matched, and an error occurs in your business logic, it's probably not correct toreject
with the error. In that case, you'd want to construct aReply
that describes your error.In the
todos
example, once the request has gotten through the filters and arrived to thehandler
function, it chooses to return responses with the correct status codes instead of rejecting.It may be worth adding some pattern to ease that?
So, every time we return Err(warp::reject::something())
, we don't actually say "abort this request completely", we do say "reject this branch of filters and try another one, if any", and thus, we do trigger, another .or()
branch.
This exactly what happens in your example:
let context_extractor: warp::filters::BoxedFilter<(Database,)> = warp::any().and_then(move || {
std::future::ready(if called.swap(true, std::sync::atomic::Ordering::Relaxed) {
println!("second call");
Ok(Database::new())
} else {
println!("first call");
Err(warp::reject::custom(MyRejection))
})
}).boxed();
Here, the post_graphql_filter
runs after trying the branch with post_json_filter
exactly because the context_extractor
filter rejects this branch and switches to another one. Nothing in juniper_warp
triggers it.
To avoid switching to another .or()
branch, we should use the .recover()
filter, where do the inspection whether the Rejection
contains our cause, and if so, return a Reply
immediately, or reject into other branches.
However, we cannot write such .recover()
filter inside juniper_warp
, because we cannot know the exact user-defined error being used. That's why, it should be specified from the user-side, along with the context_extractor
(something like this):
let context_extractor: warp::filters::BoxedFilter<(Database,)> = warp::any()
.and_then(move || {
std::future::ready(if called.swap(true, std::sync::atomic::Ordering::Relaxed) {
println!("second call");
Ok(Database::new())
} else {
println!("first call");
Err(warp::reject::custom(MyRejection))
})
})
.recover(|rejection| {
// `MyRejection` should impl `warp::Reply`
// and `Clone`, because `find` returns `Option<&T>` only =(
rejection.find::<MyRejection>().cloned().ok_or(rejection)
})
.boxed();
In #1222 I'll describe this clearly in the docs and will provide an example.
Also, regarding rejects inside make_graphql_filter
, it seems that some other cases should be handled too (like failing body()
or query()
filters).
from juniper.
@scottlamb so, in the end, I've ended up rewriting juniper_warp
a bit in the way that make_graphql_filter()
executes context_extractor
only once. However, Rejection
s, returned by context_extractor
, still should be handled outside, to avoid branching into other Filter
s. I've added an example demonstrating this.
from juniper.
Related Issues (20)
- string mangling on dynamic schema due to smartstring dependency HOT 5
- Rust 1.67 emitting schema non-utf-8 field names HOT 3
- Generated code fails the `clippy::str_to_string` lint HOT 3
- Interface not working as expected with imlp HOT 3
- Expected query, got subscription. HOT 3
- `juniper_actix` does not compile with the `subscription` feature enabled HOT 2
- Old version of book is still online HOT 1
- operation_name not being set in juniper_hyper library HOT 2
- I'm having issues with App Data configuration
- Looking for Help & Community HOT 2
- Gitter link resolves to 404 HOT 1
- A better way to keep graphiql updated HOT 1
- Example to integrate with Axum HOT 7
- Subscription argumennt Error using juniper_graphql_transport_ws HOT 2
- GraphQLInputObject macro fails if crate has a local type alias named "Result"
- Create new release HOT 7
- expected tuple struct or tuple variant, found function `Ok` HOT 2
- Input type, determine if key set or unset HOT 2
- `#[graphql_object]` hides syntax errors HOT 2
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 juniper.