Created
August 2, 2019 17:47
-
-
Save dvekeman/5f1cda64e8882fb94f8ede7d4852b09d to your computer and use it in GitHub Desktop.
Original post
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*original post* | |
I've come across the same problem in the past, thought about it a few times already but never came up with a proper solution. | |
Probably the approach by @rupert and @pdamoc are the best ones. | |
One other alternative would be to allow Main.elm peek into the Msg of the child pages and intercept some of them. I realize this is not the cleanest thing to do but it's the tradeof. | |
(note: this is just an approach I drafted out quickly as an example for this post and I haven't really tried it in a real application) | |
*Main.elm* | |
``` | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
SomePageMsg (SomePage.AuthFailMsg failType) -> | |
case failType of | |
AuthMsg.Unauthenticated -> handleUnauthenticated model | |
AuthMsg.Unauthorized -> handleUnauthorized model | |
SomePageMsg somePageMsg -> | |
-- standard dispatching here: SomePage.update ... | |
``` | |
In `SomePage.elm` I changed a few things | |
- Expose `Msg(..)` instead of `Msg` (not ideal but I'm not exposing the internal messages, see code below) | |
- Split up the Msg type into a plain message type and an http-with-authentication message type | |
``` | |
module SomePage exposing (Model, Msg(..), init, update, view) | |
... | |
type Msg | |
= PlainMsg PlainMsg | |
| AuthFailMsg AuthMsg.AuthFailure -- AuthFailure will be reused across all child pages but basically it's Unauthenticated (401) or Unauthorized (403) | |
| AuthSuccessMsg AuthSuccessMsg | |
type PlainMsg = ... -- These are the regular messages FetchData, SetFieldValue, ... | |
type AuthSuccessMsg -- HTTP Result which succeeded authentication and authorization (but might still fail on something else) | |
= RequestPerformed (Result Http.Error BasicAuthResponse) | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
PlainMsg submsg -> | |
... | |
-- Handled in Main.elm | |
AuthFailMsg _ -> | |
( model, Cmd.none ) | |
-- 'Ok' processing | |
AuthSuccessMsg (RequestPerformed (Ok response)) -> | |
... | |
-- Any other HTTP error (Timeout, HTTP 500, ...) | |
-- (or fallback in case Main does not handle the message) | |
AuthSuccessMsg (RequestPerformed (Err error)) -> | |
... | |
``` | |
It does mean that I need to wrap the messages in this page: | |
*SomePage.elm (C'ud)* | |
``` | |
view : Model -> Html Msg | |
view model = | |
... | |
Html.button | |
[ Html.onClick (PlainMsg NoAuthRequest) ] | |
[ ... ] | |
-- Note the `withAuth` | |
someHttpGet : String -> Cmd Msg | |
someHttpGet url = | |
Http.get | |
{ url = url | |
, expect = Http.expectJson (withAuth RequestPerformed) basicAuthResponseDecoder | |
} | |
``` | |
The `someHttpGet` function uses a helper `withAuth` to wrap the message | |
*SomePage.elm (C'ud)* | |
``` | |
withAuth : | |
(Result Http.Error a -> AuthSuccessMsg) | |
-> Result Http.Error a | |
-> Msg | |
withAuth = | |
AuthMsg.withAuth AuthFailMsg AuthSuccessMsg | |
``` | |
Which itself is a specific version of a more general `withAuth` function | |
*AuthMsg.elm* | |
``` | |
module AuthMsg exposing (AuthFailure(..), withAuth) | |
{-| This function wraps a message with unauthenticated / unauthorized checks | |
-} | |
withAuth : | |
(AuthFailure -> msg) -- ^ The message constructor in case of failure (unauthenticated | unauthorized) | |
-> (authMsg -> msg) -- ^ The message constructor in case of success | |
-> (Result Http.Error a -> authMsg) -- ^ The sub-message constructor | |
-> Result Http.Error a -- ^ The HTTP result | |
-> msg | |
withAuth failMsg successMsg toAuthMsg result = | |
if isUnauthenticated result then | |
failMsg Unauthenticated | |
else if isUnauthorized result then | |
failMsg Unauthorized | |
else | |
successMsg <| toAuthMsg result | |
type AuthFailure = Unauthenticated | Unauthorized | |
``` | |
Sorry for the lengthy post.. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment