拦截401以获取Elm中的任何响应

拦截401以获取Elm中的任何响应,elm,Elm,我正在Elm中构建一个应用程序,其中大多数API调用都受到保护;i、 e.用户需要登录API调用才能工作。如果用户未登录,他们将收到401未经授权的响应。如果任何响应是401,我希望应用程序重定向到登录页面 目前,我只为单个API调用设置了此重定向。下面是代码的精简版本,让您了解如何进行设置: -- Util/Api.elm type alias Data data = { data : data } -- Resources/Expense.elm getExpenses :

我正在Elm中构建一个应用程序,其中大多数API调用都受到保护;i、 e.用户需要登录API调用才能工作。如果用户未登录,他们将收到
401未经授权的
响应。如果任何响应是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 } ! []
基本上,我想将逻辑从
ExpenseList/Update.elm
移动到
Main/Update.elm
401
响应,这样我就可以将它用于我想要的任何请求

我尝试了很多方法,但是对于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调用标记为受保护,并在
Main.Update.Update
中捕获顶层的
401
错误?

当前,API调用由
ExpenseList/Update
模块封装。这种封装使得
Main
模块无法使用API调用结果。交互工作原理如下:
Main->FeatureModule->API

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

  • 有一个API模块,它通过生成
    任务
    s来提供低级API功能。与生成
    Cmd
    s不同,这允许调用方(如
    Main
    模块)决定如何处理
    任务的结果,这可以通过将
    任务
    转换为
    Cmd
    并将其交给Elm运行时执行来获得
  • ExpenseList.Update
    模块使用API模块创建
    任务
在这种安排下:

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