Re: HTTP request handler / middleware SRFI Lassi Kortela 05 Apr 2019 15:18 UTC
>> Great! Have you considered publishing the Chez version in Akku? >> <https://akkuscm.org/> > > Yes, but it's quite a mess now, it includes support for parsing and > writing cookies, multipart/form-data, application/x-www-form-urlencoded, > and automatic conversion of parameters. Things should be split up into > multiple libraries. Good idea :) It's great news that you have all this stuff already. Snow-Fort and Akku make it really easy to publish packages. The Scheme community is small and fairly quiet but I've been very pleasantly surprised at how high quality everything is. > It'd be nicer for the user if the first write to the body would just > flush the headers. I think PHP does it that way. Having to flush > explicitly isn't very nice :-/ I would imagine this can cause problems when composing handlers. If you use a middleware handler from a library, you should ideally be able to treat it as a black box that just works. Implicit behavior is convenient when starting out but tends to be problematic when building big systems from components because it's not clear where a problem is coming from. An application writer could start off using return values only. Then there's no need to worry about flushing headers. Only heavy-duty apps/middleware would write and flush headers explicitly. > I'd be willing to help working on this, I've been doing a lot of web > stuff ;) Thank you. This is looking great! Also, everyone who has posted in this thread likely knows more about web tech than I do, which is exactly what I hoped for ;) > Right now, my API looks a bit like this: > > (define-url-handler (get "/" account period) > ;; define a handler for "/" that only listens on GET requests. > ;; Automatically bind the url parameters `account' and `period' to parameters. > ... do something with account and period ... > ) > > (define-url-handler ((get post) "/foo" (n number) (f symbol)) > ;; listen to GET and POST, automatically try to convert n to a number > ;; and f to a symbol > ... > ) You messy library already reads better to me than most of the stable routing libraries in other languages. Love working with Lisp people :) > I have parameterized request and response objects, with various > accessors (scgi:parameter, scgi:request-method, scgi:request-uri, > set-scgi:response-header!). That seems like a good starting point for us all. > There's also some code to write "nice" access logs: Loggers would go great as their own middlewares IMHO. I recently factored out the logging stuff from a Go library: <https://github.com/lassik/go-httplog/> Go also has this same kind of middleware structure. That made it easy to do fully composable logging. > I also have rudimentary support for CSS and a Schemely version of > Javascript: > > (define-url-handler (get "/css") > (css-response > (css `(("header.ui.navbar" (background-color "#b1c800")) > (".ui.menu" (margin 0) (border-radius 0)) > ("header" (flex "0 0 auto") (background-color "#b1c800")) > ...)))) > > (define-url-handler (get "/javascript") > (parenscheme-response > `("use strict" > ($ - (lambda () > (define (dropdown-on-show) > (set-timeout window > (lambda () > (focus ($ - (ref ($ - ".ui.dropdown.active > input.search") 0)))) > 500) > #t) > (popup ($ - ".popup-button") > (object :inline #t))))))) > I've found https://github.com/http4k/http4k interesting to look at. Cool, is this similar to WSGI/Rack/Ring/etc. or something more comprehensive? > I've also found that making the interface *testable* is very important > (I haven't quite achieved that yet). You really want a nice way to send > a request object in and test things about the response. Excellent point. This is also one of the strengths of the request-handler abstraction, but allowing the manual append-header! / flush-header / append-body! operations complicates it somewhat. Have you come across <http://httpbin.org/>? It's a web server established by the author of Python's popular "requests" library, for the purpose of testing HTTP clients. This doesn't help test our router / request handler, but it does help with all the peripheral stuff (HTML form encoding/decoding libraries, etc.) And can help decide what kinds of test cases to write. > All of that code is not well-tested or in any way well-written :-/ If people are this motivated, we'll have that sorted out eventually :)