Repository: seanmonstar/warp

Issue #607: Why are all extensible structs, types, and traits hidden?
Created: 2020-06-14T06:47:27Z
I, for the life of me, cannot understand why all of the extensibility of warp is thrown behind artificial privacy mechanisms, such as pub(crate), private mods, and mod sealed.
There are so many cool things we, as users, could do with warp to make it more extensible, make libraries, standard filter-sets, etc., but we cannot, because all of the traits and structs we need (Filter, One, and Tuple, for starters) are hidden.  Why?  It makes no sense to me.  These aren't hidden implementation details.  These are the life blood of what makes warp tick, and what would provide us a way to make it tick even better in our use cases.  Those aren't supposed to go behind privacy mechanisms.  What goes into private crates are low-level implementations, backside details that can't be extended and aren't a major part of your API, and no one in any use case would need.
Filter IS the warp API (or at least a pretty big chunk), yet it is hidden away and not extendable, so we can't make our own filters to make a nice, awesome filter library; instead we MUST rely on what the developer has decreed is useful for a web server?  That doesn't seem like an open, modular strategy.  Furthermore, One/Tuple, etc. are all types and traits we would need to make library functions that can handle replies, etc. but we can't, because they are also hidden away.
It is extremely frustrating to see the tools I need locked behind the glass display case for no discernible reason.
Is there any reason you can't change all of these mechanisms to make important traits (the ones I listed, for a start) public, and then trust us to know how to program well-enough to use them?

Duplicate issue #744: How to combine nested filters?
Created: 2020-11-06T23:12:21Z
I would like to write a Rust package that implements a few "sub-endpoints" for another developer's consumer crate (e.g. for OAuth or other APIs).
For example, I have the following "integrated" code that I want to separate into two packages (the "shared" crate and a "consumer" crate).
// Integrated crate
impl InfoRefs for Repo {
    fn capabilities(&self) -> Vec<Capability>;
}

let info_refs = warp::path!(String / String / "info" / "refs")
    .map(|(owner, name)| Repo { owner, name })
    .and(warp::query::<Query>())
    .map(|(repo, query)| {
        // Build response
        Response::builder()
            .body(
                // ...
                repo.capabilities()
                // ...
            )
    });
In short, this is and(path.map, query).map
The problem is, I want to move these lines into the "shared" crate:
  // Consumer crate
  let info_refs = warp::path!(String / String / "info" / "refs")
      .map(|(owner, name)| Repo { owner, name })
-     .and(warp::query::<Query>())
-     .map(|(repo, query)| {
-         // Build response
-         Response::builder()
-             .body(
-                 // ...
-                 repo.capabilities()
-                 // ...
-             )
-     });
+    .and(git_service::info_refs);
However, this isn't currently possible because there's no way to write this info_refs function that can use both the output of the developer's own path map and the result of the query parse. Specifically, moving this to another crate would create:
// Shared crate
pub fn info_refs() -> impl Filter<...> {
    warp::query::<Query>().map(|query| {
        // ...
    })
}
Calling this from the consumer crate would result in and(path.map, query.map), which is obviously incorrect and not useful because we can no longer access the result of path.map here.
What's the recommended work around for this? There are a lot of useful types that are not exported by Warp, like Wrap, that could potentially be useful in this situation.

Closing comment (2020-11-06T23:27:25Z): Nevermind, this is probably related to #607 (although I hope my question did not come across as aggressive). I hope it would be possible to feature-gate some of these types because it's quite difficult to express some common patterns ("middleware" in general actually) without some of these types.
For example, the use case I am describing, could in the future be written as:
pub fn info_refs<F>() -> impl Wrap<F> where F: Filter, F::Extract: InfoRefs {
    warp::wrap_fn(|filter| {
        filter.and(warp::query::<Query>())
              .map(|(repo, query)| ...)
    })
}
Unfortunately, Wrap is still sealed.