如何在 ELM 应用程序中调用 API,我的代码不会处理响应数据?

Rev*_*nja 0 elm

Elm 新手可以帮助我理解为什么此代码返回我的错误“无法加载页面”?我很确定这与返回的 JSON 数据有关,我还没有弄清楚如何管理它。

基本上我是 Elm 的新手,并希望通过使用来自免费 API 的更多 JSON 数据来更进一步,任何人都可以伸出援手吗?


import Browser
import Html exposing (Html, text, pre)
import Http

-- MAIN

main = 
    Browser.element
     { init = init 
     , update = update
     , subscriptions = subscriptions
     , view = view
     }



--  MODEL

type Model
    = Failure
    | Loading
    | Success String

init : () -> (Model, Cmd Msg)
init _ = 
    ( Loading
    , Http.get
        { url = "http://api.openweathermap.org/data/2.5/weather?q=naples&APPID=mykey"
        , expect = Http.expectString GotText  
        }
    )



-- UPDATE


type Msg
  = GotText (Result Http.Error String)


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GotText result ->
      case result of
        Ok fullText ->
          (Success fullText, Cmd.none)

        Err _ ->
          (Failure, Cmd.none)



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.none



-- VIEW


view : Model -> Html Msg
view model =
  case model of
    Failure ->
      text "I was unable to load your book."

    Loading ->
      text "Loading..."

    Success fullText ->
      pre [] [ text fullText ]



UPDATE - 

This works in Ellie but not locally compiling using Elm 19


Something is off with the body of the `init` definition:

39|>  ( Loading
40|>  , Http.get
41|>      { url = "http://127.0.0.1:8080/test"
42|>      , expect = Http.expectString GotText
43|>      }
44|>  )

The body is a tuple of type:

    ( Model, Json.Decode.Decoder a -> Http.Request a )

But the type annotation on `init` says it should be:

    ( Model, Cmd Msg )

-- TYPE MISMATCH ---------------------------------------------- src/Fizzbuzz.elm

The 1st argument to `get` is not what I expect:

40|   , Http.get
41|>      { url = "http://127.0.0.1:8080/test"
42|>      , expect = Http.expectString GotText
43|>      }

This argument is a record of type:

    { expect : b, url : String }

But `get` needs the 1st argument to be:

    String

-- TOO MANY ARGS ---------------------------------------------- src/Fizzbuzz.elm

The `expectString` value is not a function, but it was given 1 argument.

42|       , expect = Http.expectString GotText
                     ^^^^^^^^^^^^^^^^^
Are there any missing commas? Or missing parentheses?

Run Code Online (Sandbox Code Playgroud)

更新 - 我进行了更改,尝试从我的 Go 网络服务器向 Elm 发送任何 JSON,以确认您的回答所依赖的一些内容,谢谢。

ada*_*ish 6

您正在尝试进行跨域请求。这样做的机制称为CORS(跨源资源共享)。要启用 CORS 请求,服务器必须使用access-control-allow-origin响应标头明确允许来自您的域的请求。开放天气 API 没有此标头,因此当浏览器尝试请求数据时,它会被浏览器安全限制阻止。

您需要执行以下操作之一:

  • 要求 openweather 将您的域列入白名单以获取 CORS 响应标头(不太可能)
  • 代理来自您自己域服务器的 openweather 请求

后者更有可能成为可能,但这也意味着您将能够为您的 API 密钥保密。如果您从客户端发出天气请求,那么加载您网页的任何人都将能够在其浏览器发出的请求中以及您网页的源代码中看到 API 密钥。

@5ndG 给出的工作示例使用的 API 具有access-control-allow-origin显式将 Ellie 列入白名单的响应标头,这就是它在那里工作的原因。您可以使用浏览器的开发工具查看请求和响应,以了解情况是否如此。

祝你好运!