Nicolas Heimann
Nicolas Heimann

Reputation: 2581

toJson instance single value

I am able to json-encode my data

import Data.Aeson                       (ToJSON, toJSON, (.=), object)
import qualified Data.Text      as T
import qualified Data.Text.Lazy as L

data ServiceResponse = ReadServiceResponse  L.Text
                     | GenericServiceError  Int L.Text

instance ToJSON ServiceResponse where
    toJSON (ReadServiceResponse text)      = object ["text" .= text]
    toJSON (GenericServiceError code text) =
        object ["code" .= code, "message" .= text]

For data having only one "scalar" value (e.g. String, Int, L.Text, ...) I would like to get a scalar representation instead of an object. For example the ReadServiceResponse should be encoded into a json string instead of an object like

{
    text: "hi I'm some text."
}

I tried

instance ToJSON ServiceResponse where
    toJSON (ReadServiceResponse text) = text

which does not compile

• Couldn't match expected type ‘aeson-1.3.1.1:Data.Aeson.Types.Internal.Value’ with actual type ‘L.Text’

Should I transform text into a Data.Aeson.Types.Internal.Value (How can i do that)? Thanks in advance for any help

Upvotes: 0

Views: 148

Answers (1)

chepner
chepner

Reputation: 531315

Since toJSON must return a value of type Value, you can't return text by itself; it has to be wrapped with the String data constructor.

toJSON (ReadServiceResponse text) = String text

Note that since String :: T.Text -> Value, this requires you to use the strict implementation of Text in the definition of ReadServiceResopnse:

data ServiceResponse = ReadServiceResponse  T.Text -- not L.Text
                     | GenericServiceError  Int L.Text

or doing a conversion in toJSON:

toJSON (ReadServiceResponse text) = String . T.pack . L.unpack $ text

Upvotes: 2

Related Questions