1

我正在为大学课程制作 REST API:

data Course = Course {
    id :: Maybe Text,
    name :: Text,
    deleted :: Bool
} deriving(Show, Generic)

instance FromJSON Course
instance ToJSON Course

我想允许deleted在序列化 JSON 结构中是可选的,但在我的应用程序中不允许。如果解析时未指定,我想设置deleted为。False

我可以为 编写一个手动实例FromJSON,但我不想为所有字段都写出来。我想声明如何处理已删除的内容,并让自动实例处理其他所有内容。

我该怎么做?

4

1 回答 1

2

据我所知,没有办法自定义通用实例,但您可以稍微不同地构造您的类型:

data Course = Course
    { courseId :: Maybe Text    -- Don't use `id`, it's already a function
    , name :: Text
    } deriving (Show, Generic)

data Deletable a = Deletable
    { deleted :: Bool
    , item :: a
    } deriving (Show)

instance FromJSON Course
instance ToJSON Course

instance FromJSON a => FromJSON (Deletable a) where
    parseJSON (Object v) = do
        i <- parseJSON (Object v)
        d <- v .:? "deleted" .!= False
        return $ Deletable d i
    parseJSON _ = mzero

现在你可以做

> let noDeleted = "{\"name\":\"Math\",\"courseId\":\"12345\"}" :: Text
> let withDeleted = "{\"name\":\"Math\",\"courseId\":\"12345\",\"deleted\":true}" :: Text

> decode noDeleted :: Maybe (Deletable Course)
Just (Deletable {deleted = False, item = Course {courseId = Just "12345", name = "Math"}})

> decode noDeleted :: Maybe Course
Just (Course {courseId = Just "12345", name = "Math"})

> decode withDeleted :: Maybe (Deletable Course)
Just (Deletable {deleted = True, item = Course {courseId = Just "12345", name = "Math"}})

> decode withDeleted :: Maybe Course
Just (Course {courseId = Just "12345", name = "Math"})

现在,您可以选择在需要时将课程标记为可删除,并且FromJSON实例会处理所有事情。

于 2014-10-08T15:17:09.937 回答