Elm:在 JSON 中解析状态代码(带有潜在的错误消息)
Elm: Parsing a status code (with a potential error message) in JSON
我在用 Elm 解析 JSON 时遇到了一些困难。我似乎没有掌握基础知识,但出于某种原因,这一小块 JSON 让我感到困惑。
场景如下:我将发布到 JSON API,它将 return 使用以下两种格式之一:
如果请求成功:
{
"status": "success",
"post": { ... }
}
如果失败:
{
"status": "error",
"message": "Some error message"
}
我正在尝试将此 JSON 响应编码为这些数据类型:
type RequestStatus = Success | Error String
type alias CreatePostResponse =
{ status : RequestStatus
, post : Maybe Post }
到目前为止,我运气不好。我一直在浏览 JSON.Decode tutorial and this Thoughtbot article 作为指南,但似乎都没有把我带到正确的地方。这是我目前的代码:
createPostResponse : Decoder CreatePostResponse
createPostResponse =
succeed CreatePostResponse
|: (("status" := string) `andThen` (("error" := string) `andThen` decodeStatus))
|: maybe ("post" := post)
decodeStatus : String -> String -> Decoder RequestStatus
decodeStatus status errorMessage =
succeed (case status of
"success" -> Success
"error" -> Error errorMessage
_ -> Error "unknown")
显然这会产生各种类型错误并且无法编译,但我一直无法想出一个好方法将字符串从 "message" 字段获取到 RequestStatus
类型。
有没有人有什么想法?
这是一小段工作代码,应该可以满足您的需求。为了具体起见,我冒昧地假设了 Post
类型的基本形状。
import Json.Decode exposing (..)
type alias Post = { title: String, body: String }
type RequestStatus = Success Post | Error String
post: Decoder Post
post = object2 Post ("title" := string) ("body" := string)
requestStatusData: String -> Decoder RequestStatus
requestStatusData status =
case status of
"success" -> object1 Success ("post" := post)
"error" -> object1 Error ("message" := string)
_ -> fail <| status ++ " is not a valid value for request status"
decodeStatus : Decoder RequestStatus
decodeStatus =
("status" := string) `andThen` requestStatusData
首先,我将 RequestStatus
和 CreatePostResponse
类型从里到外翻转:而不是 CreatePostResponse
具有 RequestStatus
和 Maybe Post
,这需要为了保持彼此同步,RequestStatus
类型本身模拟了一个事实,即成功有一个 post,而错误没有。新的 RequestStatus
读起来更像惯用的 Elm。
然后我从上到下接近解码:
为了将一些JSON解码为RequestStatus
,我们首先将JSON对象中的"status"
属性反序列化为一个字符串,然后我们根据 "status"
的内容反序列化其余部分。这样做的惯用方法是使用 andThen
(看起来你知道这一点,但还没有完全完善它与其余部分的配合方式)。这转化为:
decodeStatus : Decoder RequestStatus
decodeStatus =
("status" := string) `andThen` requestStatusData
andThen
解码一条记录,然后将该记录传递给一个函数,该函数完成其余的解码,因此 requestStatusData
需要看起来像:
requestStatusData: String -> Decoder RequestStatus
requestStatusData
是 Success Post
或 Error String
。所以我们需要两个分支,然后与状态 "success"
和 "error"
相关联(加上一个默认值以捕获格式错误的状态):
requestStatusData status =
case status of
"success" -> makeSuccessWithPost
"error" -> makeErrorWithString
_ -> fail <| status ++ " is not a valid value for request status"
我们填写 makeSuccessWithPost
和 makeErrorWithString
实现。 Json.Decode
中的 objectN
函数提供了一种解码组件的功能,然后将它们提供给构造函数(或其他函数):
object1 Success ("post" := post)
首先使用定义为 post
的解码器解码 "post"
属性,然后在结果上调用 object1
(Success
) 的第一个参数.同样,
object2 Post ("title" := string) ("body" := string)
使用string
解码器解码"title"
,然后使用string
解码器解码"body"
,然后用两个解码字符串调用Post
函数作为它的论点。所以我们最终得到:
requestStatusData status =
case status of
"success" -> object1 Success ("post" := post)
"error" -> object1 Error ("message" := string)
_ -> fail <| status ++ " is not a valid value for request status"
最后一步是填写post
解码器,上面说的是object2
.
的标准应用
总的来说,我认为我已经以相当标准、惯用的 Elm 风格处理了这个问题,但我是新手,我可能会犯一些错误。它确实有效!最后一点:我认为 RequestStatus
类型实际上不是必需的; Elm 核心库中的 Result
类型捕捉了具有成功和失败模式的类型的概念。你可以使用
Result String Post
而不是 RequestStatus
而不会丢失任何功能(您需要稍微更改 requestStatusData
但我会将其留作 reader... 的练习)。
我在用 Elm 解析 JSON 时遇到了一些困难。我似乎没有掌握基础知识,但出于某种原因,这一小块 JSON 让我感到困惑。
场景如下:我将发布到 JSON API,它将 return 使用以下两种格式之一:
如果请求成功:
{
"status": "success",
"post": { ... }
}
如果失败:
{
"status": "error",
"message": "Some error message"
}
我正在尝试将此 JSON 响应编码为这些数据类型:
type RequestStatus = Success | Error String
type alias CreatePostResponse =
{ status : RequestStatus
, post : Maybe Post }
到目前为止,我运气不好。我一直在浏览 JSON.Decode tutorial and this Thoughtbot article 作为指南,但似乎都没有把我带到正确的地方。这是我目前的代码:
createPostResponse : Decoder CreatePostResponse
createPostResponse =
succeed CreatePostResponse
|: (("status" := string) `andThen` (("error" := string) `andThen` decodeStatus))
|: maybe ("post" := post)
decodeStatus : String -> String -> Decoder RequestStatus
decodeStatus status errorMessage =
succeed (case status of
"success" -> Success
"error" -> Error errorMessage
_ -> Error "unknown")
显然这会产生各种类型错误并且无法编译,但我一直无法想出一个好方法将字符串从 "message" 字段获取到 RequestStatus
类型。
有没有人有什么想法?
这是一小段工作代码,应该可以满足您的需求。为了具体起见,我冒昧地假设了 Post
类型的基本形状。
import Json.Decode exposing (..)
type alias Post = { title: String, body: String }
type RequestStatus = Success Post | Error String
post: Decoder Post
post = object2 Post ("title" := string) ("body" := string)
requestStatusData: String -> Decoder RequestStatus
requestStatusData status =
case status of
"success" -> object1 Success ("post" := post)
"error" -> object1 Error ("message" := string)
_ -> fail <| status ++ " is not a valid value for request status"
decodeStatus : Decoder RequestStatus
decodeStatus =
("status" := string) `andThen` requestStatusData
首先,我将 RequestStatus
和 CreatePostResponse
类型从里到外翻转:而不是 CreatePostResponse
具有 RequestStatus
和 Maybe Post
,这需要为了保持彼此同步,RequestStatus
类型本身模拟了一个事实,即成功有一个 post,而错误没有。新的 RequestStatus
读起来更像惯用的 Elm。
然后我从上到下接近解码:
为了将一些JSON解码为
RequestStatus
,我们首先将JSON对象中的"status"
属性反序列化为一个字符串,然后我们根据"status"
的内容反序列化其余部分。这样做的惯用方法是使用andThen
(看起来你知道这一点,但还没有完全完善它与其余部分的配合方式)。这转化为:decodeStatus : Decoder RequestStatus decodeStatus = ("status" := string) `andThen` requestStatusData
andThen
解码一条记录,然后将该记录传递给一个函数,该函数完成其余的解码,因此requestStatusData
需要看起来像:requestStatusData: String -> Decoder RequestStatus
requestStatusData
是Success Post
或Error String
。所以我们需要两个分支,然后与状态"success"
和"error"
相关联(加上一个默认值以捕获格式错误的状态):requestStatusData status = case status of "success" -> makeSuccessWithPost "error" -> makeErrorWithString _ -> fail <| status ++ " is not a valid value for request status"
我们填写
makeSuccessWithPost
和makeErrorWithString
实现。Json.Decode
中的objectN
函数提供了一种解码组件的功能,然后将它们提供给构造函数(或其他函数):object1 Success ("post" := post)
首先使用定义为
post
的解码器解码"post"
属性,然后在结果上调用object1
(Success
) 的第一个参数.同样,object2 Post ("title" := string) ("body" := string)
使用
string
解码器解码"title"
,然后使用string
解码器解码"body"
,然后用两个解码字符串调用Post
函数作为它的论点。所以我们最终得到:requestStatusData status = case status of "success" -> object1 Success ("post" := post) "error" -> object1 Error ("message" := string) _ -> fail <| status ++ " is not a valid value for request status"
最后一步是填写
post
解码器,上面说的是object2
. 的标准应用
总的来说,我认为我已经以相当标准、惯用的 Elm 风格处理了这个问题,但我是新手,我可能会犯一些错误。它确实有效!最后一点:我认为 RequestStatus
类型实际上不是必需的; Elm 核心库中的 Result
类型捕捉了具有成功和失败模式的类型的概念。你可以使用
Result String Post
而不是 RequestStatus
而不会丢失任何功能(您需要稍微更改 requestStatusData
但我会将其留作 reader... 的练习)。