Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Request (and related) #192

Closed
Fishrock123 opened this issue Jul 8, 2020 · 2 comments
Closed

Rework Request (and related) #192

Fishrock123 opened this issue Jul 8, 2020 · 2 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@Fishrock123
Copy link
Member

Fishrock123 commented Jul 8, 2020

This is essentially a summary of the major improvements to Surf I've been trying to make. there is a lot of overlap with disparate existing issues, which I've linked where appropriate.


In order to improve middleware for Surf (#131), and bring it more in-line with Tide, the following changes should be made:

  • Middleware should operate on surf::Request, surf::Response rather than http_types::Request, etc.
  • surf::Request should be changed to be a more minimalized wrapper around http_types::Request (similar to Response and Tide.)

And also for code hygiene, Request should probably not be all of these at once (#152):

Additionally related, Client should not be generic (#69), (comment on 105), and Middleware may want to be accessible from the present Middleware stack for complete retry/redirect purposes (#169), (#18).

Note: Making Client 1:1 with an actualized Request helps this but doesn't work for keep-alive or http2/3+.


There is a clean but slightly less ergonomic way to solve most of the API issues here:

  • Have surf::Request be like tide::Request, only hold http_types::Request.
  • Do not internally hold a surf::Request
  • Have Client::send(req: impl Into<surf::Request>) -> BoxedFuture rather than making anything be directly await-able.
    • (Since that requires internal storage and causes the awaited structure to be consumed.)
  • Have Middleware be stored on the Client. (Allow applying middleware before know about request uri and methods #126)
  • Have a separate RequestBuilder similar to tide::ResponseBuilder.
  • Have RequestBuilder::send() be a short-cut for "build and make a new Client and call .send(self) on it".
  • Have surf::method() return a RequestBuilder.
let res = surf::post(url)
    .header(h, v)
    .body(b)
    .send().await?;

With middleware:

let req = surf::post(url)
    .header(h, v)
    .body(b);
let client = surf::client()
    .middleware(m);
let res = client.send(req).await?;

Regarding Client being generic, I see two paths. Either #69, or just making the structure's properties be directly determined by compile-time configuration. dyn is probably better if we want people to be able to pass external clients that implement some kind of trait. In that case, surf::client_from(trait) or similar could exist, or possibly even .send::<ClientType>().
Update: see #193 "dyn HttpClient". (Merged)

Ideally I think that Client would be the thing that actualizes/sends Requests and holds the middleware stack, similar to what #109 asks for.


This was an older WIP, see #194 for a full compiling patch of the above proposal!

I have a WIP patch of some of this stuff, but in the form of a SurfBuilder, which has a structure like so and is not much cleaner than today, although it does allow middleware to operate on surf::Request and surf::Response. I prefer the approach I described above.

// not great
pub struct SurfBuilder<C: HttpClient + Unpin + Send + Sync> {
    client: C,
    req: Option<Request>,
    middleware: Option<Vec<Arc<dyn Middleware<C>>>>,
    fut: Option<BoxFuture<'static, Result<Response>>>,
}

tl;dr things become much cleaner and simpler if:

@goto-bus-stop
Copy link
Member

great post, i think i agree with this direction. thanks for writing this up!

should we still have surf::post at all if it's just a shorthand for like, surf::RequestBuilder::post()? :)

Have Client::send(req: impl Into<surf::Request>) -> BoxedFuture rather than making anything be directly await-able.

strongly agree with this in particular—it makes the API a bit less "nice" (for some values of nice) but it's better both for the implementation and for actually modeling how requests are sent (client sends requests, requests don't send themselves).

Fishrock123 added a commit to Fishrock123/surf that referenced this issue Jul 9, 2020
Fishrock123 added a commit to Fishrock123/surf that referenced this issue Jul 24, 2020
A practical implementation of http-rs#192

Some form of this is required in order to make middleware use
`surf::Request` and `surf::Response`. Doing so means that those types,
particularly request, must own their related `http_types` data.
Refs:  http-rs#131

This necessitates that `surf::{method}()` return some kind of builder,
as is include here as `RequestBuilder`, which includes methods for
the common request manipulations when creating new requests.
As added convience, the builder can be awaited directly, but does not
allow for middleware without use of `Client` due to confusing
semantics regarding combining per-request and per-client middleware.

PR-URL: http-rs#194
Fishrock123 added a commit to Fishrock123/surf that referenced this issue Jul 28, 2020
A practical implementation of http-rs#192

Some form of this is required in order to make middleware use
`surf::Request` and `surf::Response`. Doing so means that those types,
particularly request, must own their related `http_types` data.
Refs:  http-rs#131

This necessitates that `surf::{method}()` return some kind of builder,
as is include here as `RequestBuilder`, which includes methods for
the common request manipulations when creating new requests.
As added convience, the builder can be awaited directly, but does not
allow for middleware without use of `Client` due to confusing
semantics regarding combining per-request and per-client middleware.

PR-URL: http-rs#194
Fishrock123 added a commit to Fishrock123/surf that referenced this issue Jul 30, 2020
A practical implementation of http-rs#192

Some form of this is required in order to make middleware use
`surf::Request` and `surf::Response`. Doing so means that those types,
particularly request, must own their related `http_types` data.
Refs:  http-rs#131

This necessitates that `surf::{method}()` return some kind of builder,
as is include here as `RequestBuilder`, which includes methods for
the common request manipulations when creating new requests.
As added convience, the builder can be awaited directly, but does not
allow for middleware without use of `Client` due to confusing
semantics regarding combining per-request and per-client middleware.

PR-URL: http-rs#194
@Fishrock123
Copy link
Member Author

Done in #194.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants