Github Gists Rest APIに応答するJSONには、Haskellのキーワード が含まれていますtype
。しかしtype
、レコードフィールドとして使用することはできませんでした。
したがって、AesonのGeneric FromJSON / ToJSONインスタンスの実装には使用できませんでした。
import Data.Text (Text)
import GHC.Generics (Generic)
type URL = Text
data OwnerType = User deriving (Show)
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
-- type :: Text,
site_admin :: Bool
} deriving (Generic, Show)
instance ToJSON Owner
instance FromJSON Owner
質問:そのような種類の対立に対処するための適切なアプローチはありますか?
を使用してこれを解決できTemplateHaskell
ます。ToJSON
andを書く代わりにFromJON
、キーの特定のマッピングを使用できます。
まず、タイプではないフィールドの名前を作成する必要があります。次に例を示します。
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
owner_type :: Text,
site_admin :: Bool
} deriving (Generic, Show)
これで、インスタンスderiveJSON :: Options -> Name -> Q [Dec]
を作成する関数を使用できます。fromJSON
toJSON
ここでのキーはOptions
パラメーターです。これには、fieldLabelModifier :: String -> String
フィールドの名前をJSONのキーに書き換えることができるフィールドが含まれています。したがって、ここでそれを書き換える関数を生成できます。
したがって、最初に関数を作成しますownerFieldRename :: String -> String
。
ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name
したがって、この関数"owner_type"
は、にマップされて"type"
いるを除いて、恒等関数として機能します。
これで、次のderiveJSON
ようなカスタムオプションを使用して関数を呼び出すことができます。
$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)
または完全に:
RenameUtils.hs
:
module RenameUtils where
ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name
MainFile.hs
:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))
import RenameUtils(ownerFieldRename)
import Data.Text (Text)
type URL = Text
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
owner_type :: Text,
site_admin :: Bool
} deriving (Show)
$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)
ここでtype
、キーとしてJSONオブジェクトを取得します。
Prelude Main Data.Aeson> encode (Owner 1 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" True)
"{\"id\":1,\"gravatar_id\":\"\",\"login\":\"\",\"avatar_url\":\"\",\"events_url\":\"\",\"followers_url\":\"\",\"following_url\":\"\",\"gists_url\":\"\",\"html_url\":\"\",\"organizations_url\":\"\",\"received_events_url\":\"\",\"repos_url\":\"\",\"starred_url\":\"\",\"subscriptions_url\":\"\",\"url\":\"\",\"type\":\"\",\"site_admin\":true}"
単純なfieldLabelModifier
関数の場合、特定の関数(特定のモジュールで定義する必要があります)を記述する必要はありません。ここでラムダ式を使用することもできます。
MainFile.hs
:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))
import Data.Text (Text)
type URL = Text
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
owner_type :: Text,
site_admin :: Bool
} deriving (Show)
$(deriveJSON defaultOptions {fieldLabelModifier = \x -> if x == "owner_type" then "type" else x} ''Owner)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加