Open vittoriom opened 8 years ago
How about just writing your own handler, which then deals with the HttpResponse any way you like?
Because if I understand correctly how it works, even if I write my own handler I have to return a response in the closure and I don't have one yet. Can you elaborate some more on how I could do that?
Well if you're saying you don't have the necessary information to return a response yet, could you not perform the steps to obtain that information in the handler? I'm thinking about something like the following, in this scenario the missing information would be a String:
func customHandler( informationGetter: () -> String ) -> ( HttpRequest -> HttpResponse) {
return { request in
let externalInformation = informationGetter()
return HttpResponse.OK(HttpResponseBody.Text("Response: \(externalInformation)"))
}
}
Maybe I didn't make myself clear enough, but that's what I meant with "asynchronous". When I get a request, I have to perform some stuff before I know what I will have to return.
In the scenario you wrote, there is no asynchronous stuff going on, it should be more like:
func customHandler( informationGetter: () -> String ) -> ( HttpRequest -> HttpResponse) {
return { request in
let externalInformation = informationGetter().onCompletion { informationNeeded in
//what now? The following line wouldn't work of course
//return HttpResponse.OK(HttpResponseBody.Text("Response: \(externalInformation)"))
}
return //return what?
}
}
while I expect a server library to support something more similar to:
func customHandler( informationGetter: () -> String ) -> ( HttpRequest -> HttpResponse) {
return { (request, completion) in
let externalInformation = informationGetter().onCompletion { informationNeeded in
//perform some stuff
completion(myResponse)
}
}
}
Oh, I see what you mean. You're right, my proposal is still synchronous.
@vittoriom hi man
For now you could use dispatch_semaphore to wait for the end of informationGetter().onCompletion : https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW24
Swifter should expose some kind of promises chaining.
best dk
Hi @glock45 I appreciate your reply, but writing semaphore-based request handlers is not an option at the moment. Thanks anyway!
This sounds like the perfect use case for promises, since you don't yet have the response body but return a promise that you will create it later
I think it is pretty reasonable for an HTTP server today to be asynchronous-first, given that every non-trivial server is going to hit some kind of persistence engine or make network calls itself.
What would you guys think about something like:
server["/hello"] = { request, response in
DB.ExampleAsyncCall.find {
response.status = .OK
response.body = .HTML("You asked for " + request.url)
response.send()
}
}
or
server["/hello"] = { request, response in
DB.ExampleAsyncCall.find {
response.status = .OK
response.send(.HTML("You asked for " + request.url))
}
}
I agree with @julien-c
:+1: ...also.. with @julien-c proposition we will solve https://github.com/glock45/swifter/issues/1
Not sure what DB.ExampleAsyncCall.find
is supposed to be, but I would use an established pattern like Promises and Futures, so the handler closure only takes the request and returns a response future.
My DB.ExampleAsyncCall.find()
is your informationGetter().onCompletion()
:grin:
It's way simpler to do completion callbacks, à la Express.js – but nothing prevents you from dropping a Promise implementation there if you need (I know of FutureKit
, PromiseKit
, BrightFutures
). He who can do more, can do less.
Any ETA on this?
I ran into this as well, looking to implement a simple proxy server. I want to have Swifter listen and handle the connection, and then my handler will make a connection to somewhere else (different protocol) and stream the data back to the Swifter connection.
I've done this now by creating my own HttpHandlers extension. The reading I'm doing from the other side is asynchronous, so I have to run it asynchronously.
I've implemented this by handing off the socket to the stream handler, similar to what the WebSocket handler does, but then HttpServerIO.handleConnection closes the socket as soon as the handler is set up. I hacked it so that if the socket is passed off to the handler it is not closed in handleConnection. That works for me, but it'd be nice to have support for this baked in.
@julien-c Is your suggestion implemented in Swifter so far? I am doing similar proxy server as @fdstevex 's in my project. If asynchronous handler is not modified yet, I may switch to @fdstevex 's approach. Anyway, thanks for you guys' contribution for making this easy to use httpserver for swift
First of all, hats off to the creator of this library. This is the only Swift "client-side server" (I want to run a small API server on my user's machine) I was able to find. But it desperately needs some async support, especially as a majority of workflows when writing servers are async and most users using a library will have limited knowledge of how to extend it to fit their needs :)
Any update on async support? I think this library is more lightweight than GCDWebServer but would be really great if we could get async support baked in.
I ended up switching to https://github.com/thecatalinstan/Criollo
I ended up switching to https://github.com/thecatalinstan/Criollo
Hey! Thanks for this, I will check this out :D
I finally wrote an asynchronous, lightweight HTTP Server based on Socket in pure Swift, which can run well on iOS/macOS/tvOS: https://github.com/isaced/Aoxiang
Hi, we're planning to use your server instead of
GCDWebServer
, but we need to asynchronously handle requests. This means that, when specifying a request handler, we don't want to immediately return aHttpResponse
but be able to pass this to some kind of completion handler. Do you think this could be a welcome improvement to theswifter
project? Also, would you be able to do it?Thanks!