interceptors

martinklepsch 2018-11-12T13:07:57.013900Z

@ikitommi I really like that the queue and stack are first order parts of the context — what are your thoughts on that with regards to what should be part of the interceptor-spec?

2018-11-12T14:11:24.014900Z

@ikitommi, I’ll be out-of-pocket for the next couple of weeks but will give it thought. Thanks!

ikitommi 2018-11-12T15:40:58.022600Z

@martinklepsch I think the spec should be just data, with no implementing classes. Spec would be about the latter example: an interceptor map with optional :enter, :leave and :error stages, all of ctx => ->ctx, a context map, with :request, :response, :queue (in enter stage), :stack (implementation detail) and unwrapped exception as :error (in error stage).

ikitommi 2018-11-12T15:43:41.024300Z

the ctx => ->ctx would mean "from context to something that can be turned into a context", like a core.async channel.

ikitommi 2018-11-12T15:58:20.027400Z

btw, Sieppari should work now on cljs too, thanks to @richiardiandrea (core.async & promesa)

richiardiandrea 2018-11-12T16:03:45.032200Z

We have it now in a couple of cljs lamdbas, however some colleagues are finding a bit tough to wrap their around the flow, top down and the bottom up. I am not sure we will keep it in cause in lamdba functions, especially in JS ones, you don't have many use cases where you want to wrap...or put it in another way, you can always write things pipeline style with the last step returning the response. I would really like to see a fully fledged interceptor app to understand if we are doing things correctly tbh

martinklepsch 2018-11-12T16:57:32.039800Z

I would actually find it a bit sad if the concepts of request and response would be baked in since interceptors are a much more generic pattern

martinklepsch 2018-11-12T16:57:58.040800Z

But just so I understand - is your primary idea to spec the map describing an interceptor or also how the chain gets executed?

ikitommi 2018-11-12T16:58:43.041Z

Request and response could be anything?

ikitommi 2018-11-12T16:59:16.041800Z

it’s either request->request steps or context->context steps where the original payload is under request.

martinklepsch 2018-11-12T16:59:29.042400Z

Right but mentioning/expecting those keys could be confusing in other situation s

ikitommi 2018-11-12T17:00:03.043200Z

maybe better name for those?

martinklepsch 2018-11-12T17:00:04.043400Z

What’s a payload?

ikitommi 2018-11-12T17:00:46.044100Z

something that is the input to the execution?

ikitommi 2018-11-12T17:01:43.044300Z

(def i {:enter #(update :request inc)})
(execute [i i] 1) ; => 3

ikitommi 2018-11-12T17:02:41.045200Z

(defn execute [interceptors request] …)

martinklepsch 2018-11-12T17:02:55.045600Z

But isn’t the input just the context? Like in pedestal interceptors just receive the context and nothing else

ikitommi 2018-11-12T17:04:23.046500Z

could be that too, but as the context needs to be a map, you need to store the input value(s) somewhere:

(execute [i i] {:request 1})

martinklepsch 2018-11-12T17:04:58.047300Z

I have to do something else now but would love to chat more about this. Maybe it’s easiest if we just chat about this in a hangout some time?

ikitommi 2018-11-12T17:05:19.048Z

sure!

martinklepsch 2018-11-12T17:07:28.050200Z

You can send me an invite to <mailto:martinklepsch@googlemail.com|martinklepsch@googlemail.com> - I’m flexible most days so just send me something that works for you (Except tomorrow where I’m busy all day)

ikitommi 2018-11-12T18:08:28.055700Z

@richiardiandrea I think the normal promise/promesa chain is much better for simple things. The two-way Interceptors are good for base for reusable abstractions like in the web-servers: mounting an exception-handling interceptor to the root will ensure that all exceptions are always handled gracefully. Same for request/response formatting: :enter decodes the body, :leave encodes the response body and :error returns the formatting errors in the negotiated format. Also, as interceptors are data, one can inspect & inventory them, re-order, add request/response specs etc.

ikitommi 2018-11-12T18:09:28.056500Z

ikitommi 2018-11-12T18:10:25.057800Z

that’s from Sieppari context inspector.

richiardiandrea 2018-11-12T18:12:03.059200Z

Yep I like that part very much and the only thing I don't see in our use case is the leave part - the handler is usually returns data validated in the enters and it is pretty "dumb". The callback on success does content-specific wrapping of it

richiardiandrea 2018-11-12T18:12:19.059800Z

But that's the thing, you can do things in many ways

richiardiandrea 2018-11-12T18:13:44.061600Z

And we as a team noticed that there is a mental overhead and we were always discussing if things should be in enter or leave or handler...while it technically can go in any of those

ikitommi 2018-11-12T18:16:11.063600Z

Not sure would be of any help, but one could create a one-way “ctx=>->ctx” function chain with the interceptors too. Manifold (and thus, Yada) does this.

ikitommi 2018-11-12T18:16:37.064200Z

“enterceptors” 😉

ikitommi 2018-11-12T18:22:23.065700Z

(enter [#(update % :request inc) p/promise #(update % :request * 2)] 1 respond raise)
; =&gt; eventually respond 4

ikitommi 2018-11-12T18:24:00.066900Z

… but I think promesa & manifold (JVM) are much better at one-way chaining.

ikitommi 2018-11-12T18:26:37.068500Z

… the enter fn would be actually same as execute if the 1-arity function would be mapped into a interceptor with :enter, not into a handler of request -&gt; response. :thinking_face:

richiardiandrea 2018-11-12T18:26:43.068800Z

I think we are thinking exactly about enterceptors only 😺

richiardiandrea 2018-11-12T18:27:15.069600Z

And we had a couple of ideas around sugaring the error handling and associng in the context

richiardiandrea 2018-11-12T18:27:26.070Z

But it deviates from interceptors a lot

ikitommi 2018-11-12T18:29:32.071500Z

^:--- if that would be (interceptor {:enter t}), then functions would be turned into enters and the spec would cover both 1-way & 2-way flows easily.

richiardiandrea 2018-11-12T18:36:44.074300Z

Ah ok yes I have always wondered what was the usage of that part

richiardiandrea 2018-11-12T18:39:04.075800Z

It seems that a spec would definitely greatly help understanding the use case. We picked it because of the behaviour as data aspect and layer on top of async computation

richiardiandrea 2018-11-12T18:46:30.079200Z

So we will be experimenting with the one way flow and come up with some lib...we'll see. What sieppari definitely allowed us was too get to the "functional cori imperative shell" approach so hard to get with asyec stuff

👍 1
ikitommi 2018-11-12T18:54:17.079600Z

wrote https://github.com/metosin/sieppari/issues/14

👍 1
martinklepsch 2018-11-12T21:04:12.080800Z

@richiardiandrea Was just wondering with the sieppari + promesa stuff — would it be possible to also just use regular JS promises?

richiardiandrea 2018-11-12T21:09:02.081800Z

@martinklepsch yep I posted everything to support channels, promesa and native

martinklepsch 2018-11-12T21:11:00.082400Z

@richiardiandrea ah right, just noticed — so the promesa extension is basically for people who already use promesa to enable a more streamlined integration?

richiardiandrea 2018-11-12T21:11:34.082500Z

Yeah

martinklepsch 2018-11-12T21:13:03.083Z

Sweet, thanks for the context and sorry for not spotting that in the PR 🙂

martinklepsch 2018-11-12T21:13:25.083400Z

Also I hope you're doing well ☺️

richiardiandrea 2018-11-12T21:36:47.084200Z

Ahah yeah @martinklepsch doing well, are you coming to the Conj?

martinklepsch 2018-11-12T21:41:46.085600Z

Unfortunately not! Submitted a talk but didn't get accepted and covering trip/accomodation etc. on my own is a bit too much after spending the summer on mostly unpaid work 😄

martinklepsch 2018-11-12T21:42:19.086300Z

Have fun though, I'm very curious to see the talks, seems like there are quite a few announcements coming up

richiardiandrea 2018-11-12T21:46:43.087400Z

Yeah it looks like interesting for sure I hope to see you at the next one of in Europe at some point!