elm - 拦截 Elm 中的任何响应的 401

标签 elm

我正在 Elm 中构建一个应用程序,其中大多数 API 调用都受到保护;即用户需要登录才能进行 API 调用。如果用户未登录,他们将收到 401 Unauthorized 响应。如果任何响应是 401,我希望应用程序重定向到登录页面。

目前,我仅为单个 API 调用设置了此重定向。以下是代码的精简版本,可让您了解其设置方式:

-- Util/Api.elm
type alias Data data =
    { data : data
    }

-- Resources/Expense.elm
getExpenses : (Progress (Api.Data (List Expense)) -> msg) -> Sub msg
getExpenses msg =
    (dataDecoder expenseListDecoder)
        |> Http.get expensesEndpoint
        |> Progress.track expensesEndpoint msg

-- Main/Msg.elm
type Msg
    = ExpenseListMsg ExpenseListMsg
    | RedirectToLogin

-- Main/Update.elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ExpenseListMsg msg ->
            ExpenseList.Update.update msg model

        GoTo path ->
            model ! [ Navigation.newUrl path ]

        RedirectToLogin ->
            model ! [ Navigation.load "path/to/login" ]

-- ExpenseList/Msg.elm
type ExpenseListMsg
    = GetExpensesProgress (Progress (Api.Data (List Expense)))
    | SetLoading

-- ExpenseList/Update.elm
update : ExpenseListMsg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SetLoading ->
            { model | expenses = setExpensesLoading model.expenses } ! []

        GetExpensesProgress (Done { data }) ->
            { model | expenses = addExpenses model.expenses data } ! []

        GetExpensesProgress (Fail (BadStatus { status })) ->
            case status.code of
                401 ->
                    model ! [ msgToCmd RedirectToLogin ]

                _ ->
                    model ! []

        GetExpensesProgress (Fail error) ->
            model ! []

        GetExpensesProgress progress ->
            { model | expenses = setExpensesLoading model.expenses } ! []

本质上,我想将 401 响应的逻辑从 ExpenseList/Update.elm 移动到 Main/Update.elm,以便我可以用它来满足我想要的任何请求。

我尝试了很多方法,但没有任何方法可以与 Elm 的类型系统配合使用。例如,我想做的一件事是尝试进行中间缺少特异性的嵌套模式匹配,例如:

-- Main/Update.elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ApiCall (messageType (msg (Fail (BadStatus { status })))) ->
            case status of ->
              . . .
      . . .

我希望这样的东西能够工作并匹配一条如下所示的消息:ApiCall (ExpenseListMsg (GetExpensesProgress (Fail (BadStatus))))。不幸的是,这不是正确的 Elm 语法,因此我的代码无法编译。

如何编写一些内容,允许我将 API 调用标记为 protected 并在 Main.Update.update 的顶层捕获 401 错误?

最佳答案

目前,API调用由ExpenseList/Update模块封装。这种封装使得 API 调用结果对于 Main 模块不可用。交互工作如下:Main -> FeatureModule -> API

因为 API 提供了确定应用是否应重定向到登录页面所需的信息,并且您希望 Main 模块执行重定向,所以 Main 模块需要访问 API。因此,需要去掉封装。相反,您可以:

  • 拥有一个 API 模块,通过生成 Task 来提供低级 API 功能。与生成 Cmd 不同,这允许调用者(例如 Main 模块)决定如何处理 Task 的结果,这可以是通过将 Task 转换为 Cmd 并将其交给 Elm 运行时来执行来获取。
  • ExpenseList.Update模块使用API​​模块来创建Tasks

按照这种安排:

  • Main 模块发送高级命令到功能模块,然后功能模块使用 API 模块生成低级指令,然后将其提供给模块。
  • Main 模块不需要关心这些低级指令是什么,它只是将 Task 转换为 Cmd 并等待结果。
  • 结果返回时采用低级格式(例如成功/失败)。此时,Main 模块可以跳转并处理 401 错误的重定向。否则,它可以将结果传递给功能模块,以便它可以处理结果。

关于elm - 拦截 Elm 中的任何响应的 401,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50574477/

相关文章:

parallel-processing - 如何在Elm中合并多个效果?

ajax - Elm 中的模拟依赖

HTML 布局 : mixing [Element] and [Signal Element] in an Elm web apge

dictionary - Elm:如何合并两个字典?

http - 获取请求时出现 Elm NetworkError,但控制台表示没问题

time - 埃尔姆的时间不精确,是吗?

textarea - Elm - textarea 选择范围消失

signals - 如何在 Elm 中创建一组满足给定条件的三元组?

http - Elm - 通过 get 请求检索字符串

elm - 我可以在 JSON 解码器中使用默认值吗?