-
Notifications
You must be signed in to change notification settings - Fork 382
Adding middleware #85
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
Conversation
lib/src/client.dart
Outdated
@@ -28,6 +29,9 @@ abstract class Client { | |||
/// [BrowserClient] if `dart:html` is available. | |||
factory Client() => new IOClient(); | |||
|
|||
factory Client.handler(Handler handler, {CloseHandler onClose}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I don't like using function typedefs in parameters, because it's much harder to quickly figure out what they are. Handler
is okay since it's such a fundamental type, but I'd write void onClose()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/handler_client.dart
Outdated
import 'response.dart'; | ||
|
||
typedef Future<Response> Handler(Request request); | ||
typedef void CloseHandler(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, I wouldn't make this a public type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Would be totally rid of it but no types on the right 😞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually if I can target 1.24 then we can get rid of the typedef since there's now a syntax for it. Let me know if its ok to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that sounds fine—1.24 will probably be out before this is ready for release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/middleware.dart
Outdated
closeHandler(); | ||
|
||
inner.close(); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a small thing, but it's probably more efficient to directly pass in inner.close
if closeHandler()
isn't passed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be but this ensures that close goes down through the pipeline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an aside into performance would it be better to just have
Future<Request> _defaultRequest(Request request) async => request;
Future<Response> _defaultResponse(Response response) async => response;
etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be but this ensures that close goes down through the pipeline.
I'm not sure what you mean by "goes down the pipeline".
As an aside into performance would it be better to just have
Future<Request> _defaultRequest(Request request) async => request; Future<Response> _defaultResponse(Response response) async => response;
etc
Nah, it would be trivial for implementations to hoist these if it's actually relevant to performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onClose
is a void ()
function. Within the middleware it will be unable to call inner.close
because the Client
is not passed to it. Also this makes things safer because the inner.close
is always called and someone writing a middleware can't forget to call close
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm suggesting you write:
onClose: closeHandler == null
? inner.close
: () {
closeHandler();
inner.close();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/middleware.dart
Outdated
Middleware createMiddleware({ | ||
RequestHandler requestHandler, | ||
ResponseHandler responseHandler, | ||
CloseHandler closeHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd call this onClose
, for consistency with new Client.handler()
and other Dart APIs. It's also not really a handler, since it's not invoked for a request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want this to be
onRequest, onResponse, onClose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I think handle
is good for the first two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/middleware.dart
Outdated
|
||
Middleware createMiddleware({ | ||
RequestHandler requestHandler, | ||
ResponseHandler responseHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably a good idea to add an errorHandler
here that works the same as shelf's.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want the same HijackException
functionality?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not right now. We may find a compelling use-case at some point, but I think it's a lot less crucial on the client since you aren't trying to mount a WebSocket handler as part of an existing app or whatever.
lib/src/middleware.dart
Outdated
responseHandler ??= (response) async => response; | ||
closeHandler ??= () {}; | ||
|
||
return (Client inner) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't type anonymous function parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/middleware.dart
Outdated
(Request request) async { | ||
request = await requestHandler(request); | ||
|
||
final response = await inner.send(request); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/handler_client.dart
Outdated
import 'request.dart'; | ||
import 'response.dart'; | ||
|
||
typedef Future<Response> Handler(Request request); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd put this in its own library. I know it seems silly when it's just one line of code, but having one file per type makes them a lot easier to track down in the source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
lib/src/middleware.dart
Outdated
|
||
Middleware createMiddleware({ | ||
RequestHandler requestHandler, | ||
ResponseHandler responseHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not right now. We may find a compelling use-case at some point, but I think it's a lot less crucial on the client since you aren't trying to mount a WebSocket handler as part of an existing app or whatever.
lib/src/middleware.dart
Outdated
Middleware createMiddleware({ | ||
RequestHandler requestHandler, | ||
ResponseHandler responseHandler, | ||
CloseHandler closeHandler, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I think handle
is good for the first two.
lib/src/middleware.dart
Outdated
closeHandler(); | ||
|
||
inner.close(); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be but this ensures that close goes down through the pipeline.
I'm not sure what you mean by "goes down the pipeline".
As an aside into performance would it be better to just have
Future<Request> _defaultRequest(Request request) async => request; Future<Response> _defaultResponse(Response response) async => response;
etc
Nah, it would be trivial for implementations to hoist these if it's actually relevant to performance.
@nex3 let me know if everything other than the error handler bits are looking good. If so I can start adding some documentation to it all as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything other than the error handler looks good so far.
lib/src/handler_client.dart
Outdated
import 'response.dart'; | ||
|
||
typedef Future<Response> Handler(Request request); | ||
typedef void CloseHandler(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that sounds fine—1.24 will probably be out before this is ready for release.
lib/src/middleware.dart
Outdated
closeHandler(); | ||
|
||
inner.close(); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm suggesting you write:
onClose: closeHandler == null
? inner.close
: () {
closeHandler();
inner.close();
}
@nex3 I added some error handling any particular issues with it? It follows along with what I saw in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error handling looks good.
I'm wondering if the onClose
parameter to new HandlerClient
should be optional. I can imagine handlers that don't want to do anything when they're closed—forwarding directly to an in-process shelf handler, for example.
@nex3 |
Oh, I forgot. In that case, it's fine as-is. |
I'll go ahead and add some documentation then this should be good to go 👍 |
@nex3 docs look alright? |
lib/src/client.dart
Outdated
@@ -30,6 +30,13 @@ abstract class Client { | |||
/// [BrowserClient] if `dart:html` is available. | |||
factory Client() => new IOClient(); | |||
|
|||
/// Creates a new client handler. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "Creates a new Client
from a [handler] callback." The client itself isn't a handler in the type-system sense, so we should avoid implying that in the docs.
lib/src/client.dart
Outdated
/// | ||
/// The [handler] is a function that receives a [Request] and returns a | ||
/// [Future<Response>]. It will be called when [Client.send] is invoked. This | ||
/// allows for composition of a [Client] within a larger application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This last sentence is confusing. It's not clear to me why this constructor in particular makes composition easier.
lib/src/handler.dart
Outdated
/// [Future<Response>]. | ||
/// | ||
/// A [Handler] may receive a request directly for a HTTP resource or it may be | ||
/// composed as part of a larger application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear what it means to receive a request "directly". Maybe, "A [Handler] may call an underlying HTTP implementation, or it may wrap another [Handler] or a [Client]."
lib/src/handler_client.dart
Outdated
@@ -9,15 +9,26 @@ import 'handler.dart'; | |||
import 'request.dart'; | |||
import 'response.dart'; | |||
|
|||
/// A [Handler] based HTTP client. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "[Handler] based" -> "[Handler]-based"
lib/src/handler_client.dart
Outdated
HandlerClient(this._handler, void onClose()) | ||
: _close = onClose; | ||
|
||
/// Sends an HTTP request and asynchronously returns the response. | ||
/// | ||
/// The [Handler] function will be called when this method is invoked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this line is necessary, especially since you can't directly refer to the values. Same for the similar line in close()
.
Thanks!! |
Currently a work in progress to see if this is on the right track. Will add documentation during the review process.