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

How do I call an API in an ELM app, my code won't handle the response data?

Elm 新手谁能帮我理解为什么这段代码 returns 我的错误 "could not load the page"?我很确定它与返回的数据有关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?

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

您的代码应该可以很好地处理 JSON 响应。它只会给你一个 JSON 字符串。 (虽然你可能想要解码你的 JSON 以便你可以使用它。)

我通过测试 API 尝试了您的代码 我在 Google 上发现 returns 一些 JSON: https://jsonplaceholder.typicode.com/todos/1

它工作正常,按预期显示 JSON 字符串,所以也许您的 url 有问题?

有关工作示例,请参阅 this Ellie

不丢弃更新函数中的 Http 错误可能也是个好主意;它在调试时提供有用的信息。

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

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

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

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

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

祝你好运!