Fork me on GitHub
#untangled
<
2016-04-08
>
brianosaurus00:04:08

Has anyone integrated oauth(2) into untangled?

brianosaurus00:04:39

alternatively has anyone implemented login? specifically checking the session before each request gets dispatched to it’s handler?

adambrosio03:04:46

we have, but its not open sourced yet, i would wait for a response from tony about the plan/schedule on that

juliobarros04:04:10

@adambros @brianosaurus Would it be different than any other request (using buddy)? Are there special considerations?

brianosaurus04:04:52

@juliobarros, @adambros isn’t the typical instantiation of an untangled app to hide ring? One fires up an untangled-system with some params and that’s the entry point. I’m wondering if there’s a preferred way to use an authentication fn?

adambrosio04:04:05

so i didnt write it, but the way it seems to work is by hooking into the untangled ring stack with stuff i wrote

adambrosio04:04:05

your best bet is to ask @tony.kay @davewo or @jslavin

juliobarros04:04:24

@brianosaurus: I'm not an expert. I probably wouldn't say it was to hide ring. Just to simplify the server side parser. I'd be surprised if everything else wasn't exactly the same where you could design and customize as you like.

brianosaurus05:04:34

I mispoke, it’s not untangled-system but make-untangled-server…anyway. Curious what the preferred solution is.

currentoor05:04:41

in bidi format

currentoor05:04:59

I believe you can just add you middleware in there

davewo05:04:22

@brianosaurus: I don't think there is a preferred way to handle authentication yet... We do a bit of a dance with OpenID connect to get creds in a cookie. Then we hook into the ring stack and use request-transform to validate and place creds on the request. Those creds are then extracted and evaluated inside mutate fns. The authorization part is pretty nice, but authn setup may be different for the various authn providers.

currentoor05:04:43

@davewo: You use bidi right?

currentoor05:04:21

Is there a reason we can’t add middleware like so?

davewo05:04:51

@currentoor: yep and there are also ring hooks at the beginning and end of the ring stack courtesy @adambros to inject your own handlers

davewo05:04:07

Not on my laptop or I'd send you some git links 📱

currentoor05:04:35

thanks for answering

davewo05:04:07

You're welcome, np

currentoor05:04:17

I’m having trouble getting this join query to work. Been stuck for a while even though it seems so simple.

currentoor05:04:48

I get core.cljs:264 Uncaught Error: No protocol method IWithMeta.-with-meta defined for type cljs.core/Keyword: :main

currentoor05:04:19

looks like a standard join

currentoor05:04:42

does untangled change something about the default om.next behavior?

tomjack05:04:12

what's up the stack? om.next/normalize*, maybe?

tomjack05:04:52

yeah, that's not an untangled problem I think

tomjack05:04:22

om is trying to dive into one of your [:main :singleton] and normalize the keyword

currentoor05:04:08

hmm, any suggestions?

tomjack05:04:21

it looks like you're trying to manually normalize your app state?

currentoor05:04:51

no, this was triggered by just mounting the Root component

tomjack05:04:05

yes, I mean, that's your initial app state there, and you've already manually normalized it?

tomjack05:04:15

in vanilla om, you'd pass :state (atom app-state) :normalize true in that case, as of a somwhat recent release

tomjack05:04:19

not sure about untangled

tomjack05:04:49

looking at untangled's source I guess your best option will be to denormalize your initial app state

currentoor05:04:18

so replace :current-tab [:main :singleton] with what it points to?

tomjack05:04:24

actually, maybe try just wrapping it in an atom

currentoor05:04:56

wow that worked

currentoor05:04:01

what is this magic?

tomjack05:04:21

om assumes it is normalized if it's in an atom. kind of weird, yeah...

currentoor05:04:40

ah, i think i read that somewhere

tomjack05:04:52

just curious, where did you get the :singleton idea?

currentoor05:04:23

of course i wasn’t observant enough to notice the normalization comment and atom use

tomjack05:04:07

I see, cool, I independently arrived at that pattern, good to see it elsewhere simple_smile

tony.kay14:04:20

@juliobarros: @brianosaurus Right: Not hiding it, just making it for you. As others pointed out: you can hook into the ring stack near the beginning (before the Om parsing bits) or late (as a default handler if nothing else handled it). That pretty much lets you customize the server any way you want as far as request handling. So, if you need to do various redirects...covered. Then, of course, there is the component injection into the parser (e.g. make an authorization component (Stuart Sierra component), add it to the components map on make server, and inject it into the parser environment...now you have access to it in you API handlers for making the authorization decisions on a request level.

brianosaurus16:04:51

@tom.kay thanks. That’s very helpful. I think it’s apropos to have access to auth handling on the request level since not every request requires someone to be auth’ed (the about page for example).

tony.kay16:04:18

Yep. Authentication is usually more global (do I know you (or care)) whereas authorization is request specific.

brianosaurus20:04:12

@tony.kay: FWIW: We ended up putting unauthenticated handlers into extra-routes and we made the default mutate and read handlers authenticated. It’s simple and clear.

shofetim20:04:15

@tony.kay: Great presentation last night! Thinking further about the cache invalidation problem, if I understand correctly, falcor does have the server return either the values, or paths, that a mutation may have modified. See http://netflix.github.io/falcor/documentation/jsongraph.html#the-abstract-json-graph-operations you would still be doing cache invalidation "by hand" but at least it would be at the point of the mutation, and not "find every component that may be rendering something that I may have changed, and modify that component to know that if x changes y changes too" but I don't feel like I've fully grasped what you are doing yet.

tony.kay20:04:11

@shofetim: Yes, that is what I was trying to describe. The server does return the keys that are affected. Untangled doesn't add/remove anything around that. It is Om next behavior.

tony.kay20:04:44

In Om next it is keywords affected, which implies paths in the UI

tony.kay20:04:17

but that is a form of documentation...there is no automation around re-fecth

tony.kay20:04:24

@brianosaurus: Yeah, we're not doing anything complicated simple_smile The intention is "as simple as possible while meeting all other criteria."

shofetim20:04:58

> but that is a form of documentation...there is no automation around re-fecth

shofetim20:04:22

So in Om.next it would be the parser's job to take those keys and "do something" (<- user implements their own "something")

shofetim20:04:35

But in untangled we don't have a parser so... what happens?

tony.kay20:04:01

Not really. The parser is long done by then

tony.kay20:04:45

Your networking layer could play with them, if they are returned. To be honest, you'd have to ask on #C06DT2YSY

shofetim20:04:07

ok, I think I need to read some more docs/code.

tony.kay20:04:20

But look at it this way: when you are writing the UI, you know what you are putting on the screen

tony.kay20:04:33

When you call a mutation, you know (from the docs on that mutation) what it affects

tony.kay20:04:37

You are not in isolation here

tony.kay20:04:45

It is, in practice, trivial to know what you want to re-read

tony.kay20:04:15

Most mutations: you already did an optmistic update, so you had the state before the server did. As long as there isn't an error, all is good

tony.kay20:04:41

If there is an error, we support (tx/fallback) in your original transaction, which can say what to do (e.g. undo the optimistic update)

tony.kay20:04:48

NOTE: (tx/fallback) isn't quite done yet...it is kinda half baked, and is missing a little bit of functionality (e.g. clearing the network queue is an important feature we don't have yet)

tony.kay20:04:57

How many times have you written a real app where you didn't know pretty much exactly what was going to happen when you asked the server to do something?

tony.kay20:04:22

I'm sure there are cases...just saying in practice they are rare

tony.kay20:04:46

so, i'm not too game to work on implementing a solution until I see the real concrete problem

shofetim20:04:36

That is the case I am trying solve actually. I have an app that has the user fill out a questionnaire (30-100 questions) answers are gathered up by the component, and then sent to the server. Saving the answers is no problem, that fits the pattern of small updates to records that I want the same thing to happen on the client and on the server. When the user is done with the questionnaire, they should see a list of matches (or update a list of matches, or update the scores they see on a list of matches). Only the server has logic to compare their answers against all possible matches and produce the new scores. Now I need to invalidate all or some of the matches currently on the client...

tony.kay20:04:29

Why not implement a query on the server that answers that question?

tony.kay20:04:48

send a parameter with the client timestamp or some other reference point

tony.kay20:04:54

Then if it is a single transaction, use: (om/transact! this '[(do-the-update) (app/load ...query w/parameters...)])

tony.kay20:04:50

(Note to self...we need to rename the built-in load to untangled/load)

shofetim20:04:00

Ok, so what untangled does is if the component knows it is going to need a bunch of fresh state (matches in my description above) make a query that fetches that state, and use app-load as a callback to get it?

tony.kay20:04:29

not a callback...it is a follow-on remote read. They are guaranteed to be done in order

tony.kay20:04:02

think of app/load as a local mutation that modifies local state by loading it from the remote

tony.kay20:04:16

transact the result of a remote query

shofetim20:04:22

ok, that makes more sense.

tony.kay20:04:29

same as Om, but no need to write parser logic on the client

tony.kay20:04:59

in Om you'd say: (om/transact! this '[(do-the-update) ':thing-to-read])

tony.kay20:04:19

and you'd write logic in the parser to cause the correct query to be generated

tony.kay20:04:35

and then morph it around so the server can understand it

tony.kay20:04:43

and then morph it back so your client can understand it

tony.kay20:04:36

so, we just cut the parser stuff out of the middle. Ask for exactly what you want. You can do the :without, :post-mutation, etc on app/load

tony.kay20:04:53

It is how we implement load-data and load-field

tony.kay20:04:10

In fact, I recommend reading the source of load-data