Elm:从 http 响应解码 json 并显示它
Elm: decoding json from http response and showing it
我是 Elm 的新手,我发现很难从 http 响应中解码 json。
我正在制作的应用正在调用 gravatar 并接收配置文件。
我想从响应中提取一些字段并放入记录中,该记录又显示在视图中。
这是我的代码:
-- MODEL
type alias MentorRecord =
{ displayName : String
, aboutMe : String
, currentLocation : String
, thumbnailUrl : String
}
type alias Model =
{ newMentorEmail : String
, newMentor : MentorRecord
, mentors : List MentorRecord
}
init : ( Model, Cmd Msg )
init =
( Model "" (MentorRecord "" "" "" "") [], Cmd.none )
-- UPDATE
type Msg
= MentorEmail String
| AddMentor
| GravatarMentor (Result Http.Error MentorRecord)
| RemoveMentor
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
MentorEmail newEmail ->
( { model | newMentorEmail = newEmail }, Cmd.none )
AddMentor ->
( model, getGravatarMentor model.newMentorEmail )
GravatarMentor (Ok addedMentor) ->
( Model "" addedMentor (addedMentor :: model.mentors)
, Cmd.none
)
GravatarMentor (Err _) ->
( model, Cmd.none )
RemoveMentor ->
( model, Cmd.none )
-- VIEW
view : Model -> Html Msg
view model =
div []
[ input [ placeholder "Email adress mentor", onInput MentorEmail ] []
, button [ onClick AddMentor ] [ text "Add Mentor" ]
, br [] []
, img [ src (createIconUrl model.newMentorEmail) ] []
, div [] [ text model.newMentor.displayName ]
, div [] [ toHtmlImgList model.mentors ]
]
toHtmlImgList : List MentorRecord -> Html Msg
toHtmlImgList mentors =
ul [] (List.map toLiImg mentors)
toLiImg : MentorRecord -> Html Msg
toLiImg mentor =
li [] [ img [ src mentor.thumbnailUrl ] [] ]
-- HTTP
getGravatarMentor : String -> Cmd Msg
getGravatarMentor newMentorEmail =
Http.send GravatarMentor
(Http.get (createProfileUrl newMentorEmail) decodeGravatarResponse)
createProfileUrl : String -> String
createProfileUrl email =
"https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
createIconUrl : String -> String
createIconUrl email =
"https://www.gravatar.com/avatar/" ++ MD5.hex email
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.required "aboutMe" string
|> Json.Decode.Pipeline.required "currentLocation" string
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
at [ "entry" ] mentorDecoder
如果填写了有效的电子邮件地址(即具有 Gravatar 个人资料的电子邮件地址),您会看到图标。但是这段代码还应该做的是从另一个 http 响应中提取名称、位置、关于我的信息、thumbnailUrl,将其放入列表中,并在视图中显示。如果您单击 'Add mentor'
,则不会发生这种情况
所以我猜解码部分进行得不是很好,但我不确定(可能是因为嵌套元素在列表中?)。
来自 gravatar 的回复如下所示(删除了条目中的一些字段):
{ "entry": [
{
"preferredUsername": "bla",
"thumbnailUrl": "https://secure.gravatar.com/avatar/hashinghere",
"displayName": "anne",
"aboutMe": "Something...",
"currentLocation": "Somewhere",
}
]}
Ellie 应用中的代码:https://ellie-app.com/n5dxHhvQPa1/1
entry
是一个数组。要解码数组第一个元素的内容,需要使用Json.Decode.index
.
变化:
(at [ "entry" ]) mentorDecoder
到
(at [ "entry" ] << index 0) mentorDecoder
但这里更大的问题是Gravatar不支持跨源请求(CORS),只支持JSONP。 elm-http 不支持 JSONP。您可以为此使用端口或使用第三方服务,使您能够向任意站点发出 CORS 请求。我在下面的 ellie link 中使用了后者,但您应该在实际生产应用程序中使用端口或您自己的 CORS 代理。
我还使 aboutMe
和 currentLocation
可选,因为它们不存在于我检查的配置文件中。这是 link:https://ellie-app.com/pS2WKpJrFa1/0
原函数:
createProfileUrl : String -> String
createProfileUrl email =
"https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.required "aboutMe" string
|> Json.Decode.Pipeline.required "currentLocation" string
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
at [ "entry" ] mentorDecoder
改变的功能:
createProfileUrl : String -> String
createProfileUrl email =
"https://crossorigin.me/https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.optional "aboutMe" string ""
|> Json.Decode.Pipeline.optional "currentLocation" string ""
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
(at [ "entry" ] << index 0) mentorDecoder
我是 Elm 的新手,我发现很难从 http 响应中解码 json。
我正在制作的应用正在调用 gravatar 并接收配置文件。
我想从响应中提取一些字段并放入记录中,该记录又显示在视图中。
这是我的代码:
-- MODEL
type alias MentorRecord =
{ displayName : String
, aboutMe : String
, currentLocation : String
, thumbnailUrl : String
}
type alias Model =
{ newMentorEmail : String
, newMentor : MentorRecord
, mentors : List MentorRecord
}
init : ( Model, Cmd Msg )
init =
( Model "" (MentorRecord "" "" "" "") [], Cmd.none )
-- UPDATE
type Msg
= MentorEmail String
| AddMentor
| GravatarMentor (Result Http.Error MentorRecord)
| RemoveMentor
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
MentorEmail newEmail ->
( { model | newMentorEmail = newEmail }, Cmd.none )
AddMentor ->
( model, getGravatarMentor model.newMentorEmail )
GravatarMentor (Ok addedMentor) ->
( Model "" addedMentor (addedMentor :: model.mentors)
, Cmd.none
)
GravatarMentor (Err _) ->
( model, Cmd.none )
RemoveMentor ->
( model, Cmd.none )
-- VIEW
view : Model -> Html Msg
view model =
div []
[ input [ placeholder "Email adress mentor", onInput MentorEmail ] []
, button [ onClick AddMentor ] [ text "Add Mentor" ]
, br [] []
, img [ src (createIconUrl model.newMentorEmail) ] []
, div [] [ text model.newMentor.displayName ]
, div [] [ toHtmlImgList model.mentors ]
]
toHtmlImgList : List MentorRecord -> Html Msg
toHtmlImgList mentors =
ul [] (List.map toLiImg mentors)
toLiImg : MentorRecord -> Html Msg
toLiImg mentor =
li [] [ img [ src mentor.thumbnailUrl ] [] ]
-- HTTP
getGravatarMentor : String -> Cmd Msg
getGravatarMentor newMentorEmail =
Http.send GravatarMentor
(Http.get (createProfileUrl newMentorEmail) decodeGravatarResponse)
createProfileUrl : String -> String
createProfileUrl email =
"https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
createIconUrl : String -> String
createIconUrl email =
"https://www.gravatar.com/avatar/" ++ MD5.hex email
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.required "aboutMe" string
|> Json.Decode.Pipeline.required "currentLocation" string
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
at [ "entry" ] mentorDecoder
如果填写了有效的电子邮件地址(即具有 Gravatar 个人资料的电子邮件地址),您会看到图标。但是这段代码还应该做的是从另一个 http 响应中提取名称、位置、关于我的信息、thumbnailUrl,将其放入列表中,并在视图中显示。如果您单击 'Add mentor'
,则不会发生这种情况所以我猜解码部分进行得不是很好,但我不确定(可能是因为嵌套元素在列表中?)。
来自 gravatar 的回复如下所示(删除了条目中的一些字段):
{ "entry": [
{
"preferredUsername": "bla",
"thumbnailUrl": "https://secure.gravatar.com/avatar/hashinghere",
"displayName": "anne",
"aboutMe": "Something...",
"currentLocation": "Somewhere",
}
]}
Ellie 应用中的代码:https://ellie-app.com/n5dxHhvQPa1/1
entry
是一个数组。要解码数组第一个元素的内容,需要使用Json.Decode.index
.
变化:
(at [ "entry" ]) mentorDecoder
到
(at [ "entry" ] << index 0) mentorDecoder
但这里更大的问题是Gravatar不支持跨源请求(CORS),只支持JSONP。 elm-http 不支持 JSONP。您可以为此使用端口或使用第三方服务,使您能够向任意站点发出 CORS 请求。我在下面的 ellie link 中使用了后者,但您应该在实际生产应用程序中使用端口或您自己的 CORS 代理。
我还使 aboutMe
和 currentLocation
可选,因为它们不存在于我检查的配置文件中。这是 link:https://ellie-app.com/pS2WKpJrFa1/0
原函数:
createProfileUrl : String -> String
createProfileUrl email =
"https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.required "aboutMe" string
|> Json.Decode.Pipeline.required "currentLocation" string
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
at [ "entry" ] mentorDecoder
改变的功能:
createProfileUrl : String -> String
createProfileUrl email =
"https://crossorigin.me/https://en.gravatar.com/" ++ MD5.hex email ++ ".json"
decodeGravatarResponse : Decoder MentorRecord
decodeGravatarResponse =
let
mentorDecoder =
Json.Decode.Pipeline.decode MentorRecord
|> Json.Decode.Pipeline.required "displayName" string
|> Json.Decode.Pipeline.optional "aboutMe" string ""
|> Json.Decode.Pipeline.optional "currentLocation" string ""
|> Json.Decode.Pipeline.required "thumbnailUrl" string
in
(at [ "entry" ] << index 0) mentorDecoder