Re: [elm-discuss] Re: http "middleware" options

2016-10-17 Thread Mark Hamburg
On the one hand, yes, an effects manager seems like the way to do this. On
the other hand, effects manager documentation is largely absent and the
guide basically says that effects managers are only expected to be written
by a handful of people and therefore probably aren't a general purpose
solution.

Mark

On Mon, Oct 17, 2016 at 3:25 AM, Fa Qing  wrote:

> It seems (I could be wrong; I often am)  like creating an Effects manager
> is the proper way to efficiently handle side state management.
>
> https://github.com/elm-lang/core/blob/master/src/Platform.elm
>
> An example:
>
> https://gist.github.com/maxhoffmann/240574e892bf9118aeb2dd1e8a645e0a
>
> Just a quick glance at these really helped the Elm platform come into
> better focus (namely the dispatch/routing mechanism).
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elm-discuss+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: http "middleware" options

2016-10-17 Thread Fa Qing
It seems (I could be wrong; I often am)  like creating an Effects manager 
is the proper way to efficiently handle side state management.

https://github.com/elm-lang/core/blob/master/src/Platform.elm

An example:

https://gist.github.com/maxhoffmann/240574e892bf9118aeb2dd1e8a645e0a

Just a quick glance at these really helped the Elm platform come into 
better focus (namely the dispatch/routing mechanism). 


-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: http "middleware" options

2016-10-14 Thread Mark Hamburg
Here is a quick example sketch of wrapping Http calls in request objects
and delaying conversion to commands. Untested but it compiles. (The tricky
part was handling the decoder since we need to bury the decoded type.)

type alias HttpResult a =
  Result Http.Error a

makeStringTagger : Json.Decode.Decoder a -> (HttpResult a -> msg) ->
(HttpResult String -> msg)
makeStringTagger decoder tagger =
  let
stringDecoder =
  Json.Decode.decodeString decoder
  >> Result.formatError Http.UnexpectedPayload
  in
\result -> Result.andThen result stringDecoder |> tagger

type Request msg
  = Get String (HttpResult String -> msg)
  | Command (Cmd msg)
  | Batch (List (Request msg))

get : (Result Http.Error a -> msg) -> String -> Json.Decode.Decoder a ->
Request msg
get tagger url decoder =
  Get url (makeStringTagger decoder tagger)

command : Cmd msg -> Request msg
command =
  Command

batch : List (Request msg) -> Request msg
batch =
  Batch

-- We need mapping support for Requests just like Cmds.

map : (a -> b) -> Request a -> Request b
map fn request =
  case request of
Get url tagger ->
  Get url (tagger >> fn)
Command cmd ->
  Command <| Cmd.map fn cmd
Batch list ->
  Batch <| List.map (map fn) list

-- At the service layer, we need to map back out to Cmds

toCmd : Request msg -> Cmd msg
toCmd request =
  case request of
Get url tagger ->
  Http.getString url
  |> Task.toResult
  |> Task.map tagger
  |> Task.perform (Debug.crash "never fail") identity
Command cmd ->
  cmd
Batch list ->
  Cmd.batch <| List.map toCmd list

Mark

On Fri, Oct 14, 2016 at 4:17 PM, Mark Hamburg  wrote:

> I think the requests-as-an-alternative-to-commands pattern would serve
> you here. (Sorry no link but there was a more detailed example a while
> back.)
>
> Basically, you create a type that parallels Cmd in that it supports batch
> and map functionality and you have it embody the notion of making HTTP
> requests. When the requests get to your service layer, they get turned into
> actual HTTP Cmds with the appropriate auth token attached. (Your request
> type should also allow wrapping normal Cmds so that you can pass those
> through as well.)
>
> This pattern essentially handles "middleware" as an outer wrapper on the
> model standing between your "real" model and the outside world.
>
> Mark
>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: http "middleware" options

2016-10-14 Thread Mark Hamburg
I think the requests-as-an-alternative-to-commands pattern would serve you 
here. (Sorry no link but there was a more detailed example a while back.)

Basically, you create a type that parallels Cmd in that it supports batch and 
map functionality and you have it embody the notion of making HTTP requests. 
When the requests get to your service layer, they get turned into actual HTTP 
Cmds with the appropriate auth token attached. (Your request type should also 
allow wrapping normal Cmds so that you can pass those through as well.)

This pattern essentially handles "middleware" as an outer wrapper on the model 
standing between your "real" model and the outside world.

Mark

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: http "middleware" options

2016-10-13 Thread 'Rupert Smith' via Elm Discuss
On Thursday, October 13, 2016 at 2:17:50 AM UTC+1, Fa Qing wrote:
>
> The PageLevel is calling the service level for a command. We want 
> intermediate effects, before the final command. But we don't want to just 
> issue intermediate commands either, because the state that is reacting to 
> the final command (the only one we have currently) could also be affected 
> by the intermediate command. Also, it doesn't help us refactor out the 
> (common) inputs into the service layer, such as a header value we need to 
> write out.
>
> It seems like there's a missing abstraction from the Elm architecture.
>

Hi,

I decided to make an Auth module a special case, and not use the nested TEA 
architecture for it.

I have an API like this for Auth:

port module Auth exposing (..)

type alias Credentials =
{ username : String
, password : String
}

login : Credentials -> Cmd msg
login authRequest =
sendLogin authRequest

logout : Cmd msg
logout =
sendLogout ()

unauthed : Cmd msg
unauthed =
sendUnauthed ()

port sendLogin : Credentials -> Cmd msg
port sendLogout : () -> Cmd msg
port sendUnauthed : () -> Cmd msg

The ports I can use from anywhere in the application to login, logout or on 
a 403 unauthorized to set the global state to not logged in (unauthed).

The token is part of the state of the Auth module, which is linked in to 
the global state of the Main module of the application. All Msgs to 
sub-modules go through the update method of the Main module, and use the 
nested TEA and the 'lift' function from Material.Helpers to forwad them on 
the appropriate child module. Like this:

AccountsMsg a ->
lift .accounts (\m x -> { m | accounts = x }) AccountsMsg 
Accounts.State.update a model

Passes events for the Accounts module on to it.

This could easily be adapted to pass along the current Auth token.

Another way, perhaps more convenient, could be to hold the Auth token in 
'session storage' (not local storage as that would be insecure), and 
provide a global port in the Auth module to obtain it.

As Peter suggests, make all your API call functions take the token as an 
extra arg.

I didn't need that as I opted to use cookies, which means the browser does 
it for me. However, at some point I will need to deal with APIs that insist 
on tokens in the header. I think treating auth as a bit of a special case 
and using some ports to make it more easily global across the application 
feels right to me. It is not necessary though, there are other ways of 
doing 'out messages' whereby a child module sends a message to another 
child module without resorting to using ports.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: http "middleware" options

2016-10-12 Thread Fa Qing
I understand, and appreciate the suggestion. But I'm looking for a more 
generic solution here. I can't work around cookie restraints in all of my 
use cases, unfortunately (maybe using an auth token as an example was bad 
idea).

Think about that problem of handling http errors at the root level (letting 
them "bubble up"). It's essentially the same sort of problem. 

I need to learn more about how commands actually work. Are command return 
values all fed back through a single message dispatcher (considering the 
manner in which the messages flow back down our UI hierarchy)? 

Although I think it's current hard to get a clean abstraction, it's hard to 
think of a good solution to fix it...

RootLevel _ PageLevel
  \   |
   \_> ServiceLevel

The PageLevel is calling the service level for a command. We want 
intermediate effects, before the final command. But we don't want to just 
issue intermediate commands either, because the state that is reacting to 
the final command (the only one we have currently) could also be affected 
by the intermediate command. Also, it doesn't help us refactor out the 
(common) inputs into the service layer, such as a header value we need to 
write out.

It seems like there's a missing abstraction from the Elm architecture.

But this is tricky. Effectively, I'm wishing that a service module could 
maintain some state of it's own that doesn't need to be threaded through 
the entire UI hierarchy. Or perhaps the state could still be maintained at 
the root, but the service modules would have a way of fetching state and 
communicating state change messages to the root, without passing through 
the UI hierarchy. I recognize that this puts me in dangerous territory 
though, because that is also the essence of much talk about inter-component 
communication, which I think usually heads down the wrong path (for 
understandable reasons, but wrong all the same). 




On Thursday, October 13, 2016 at 1:08:22 AM UTC+9, Rupert Smith wrote:

> On Wednesday, October 12, 2016 at 2:13:16 PM UTC+1, Fa Qing wrote:
>>
>> Let's say that every response includes a dynamic "token" header value, 
>> and every request needs to return that token in the headers.
>>
>
> Don't forget that you can use a cookie or secure cookie for this purpose. 
> Its hard to see that using a bearer token in an Authorization header is 
> better than a secure cookie, because - the browser enforces some extra 
> constraints around secure cookie to make them more secure and the cookies 
> are shared accross a domain meaning if the user pops up a second tap by 
> ctrl-clicking a link in your application, authentication can flow accross. 
> However, it seems not to be the done thing for REST APIs.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.