Переопределить, как Data.Aeson обрабатывает только одно поле моей записи

Я делаю 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, но я не хочу писать его для всех полей. Я хочу объявить, как обрабатывается удаление, и позволить автоматическому экземпляру обрабатывать все остальное.

Как бы я это сделал?


person Sean Clark Hess    schedule 08.10.2014    source источник


Ответы (1)


Насколько мне известно, нет способа настроить общий экземпляр, но вы можете немного по-другому структурировать свой тип:

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 позаботятся обо всем.

person bheklilr    schedule 08.10.2014