Re: [elm-discuss] Re: http "middleware" options
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 Qingwrote: > 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
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
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 Hamburgwrote: > 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
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
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
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.