Reputation: 983
Sometimes Haskell can be really frustrating :) I'm searching for any function to simply convert ByteString into a Value. Everything seems to be only speaking about converting directly ByteString into a final type.
My reason to do this is to convert the JSON into Value and then "pre-extract" part of the Value that contains the "real data" and only pass the "real data" (one of many types) for specific type decoding so this part is not repeated in every parseJSON instance.
EDIT: Thanks to everyone for answers, I forgot to show the real problem, maybe there is a better solution:
So, I'm building API client and the API returns everything wrapped in "data" object.
GET Dataset
{
"data": {
"id": "WkzbQMuFYuamGv3YF",
"name": "d7b9MDYsbtX5L7XAj",
...
}
}
I parse this into
data Dataset = Dataset {
name :: String,
id :: String,
...
}
Then there is more complicated type of response with pagination GET List Datasets
{
"data": {
"total": 2,
"offset": 0,
"limit": 1000,
"desc": false,
"count": 2,
"items": [
{
"id": "WkzbQMuFYuamGv3YF",
"name": "d7b9MDYsbtX5L7XAj",
...
},
...
]
}
}
For which I use more generic type as there is pagination of other things too
data PaginationList a = PaginationList {
total :: Int,
offset :: Int,
limit :: Int,
desc :: Bool,
count :: Int,
items :: [a]
} deriving Show
Now, this composes nicely and the Dataset inside parses automatically except for that "data" wrapper that I have to remove in every parsing. So this naive attempt doesn't work since in items :: [a] (where a becomes Dataset) I would try to unwrap every Dataset from "data".
Thus the solution I thought of is to pre-parse the JSON into Value to get rid of the "data" and then all the types will compose nicely.
Upvotes: 3
Views: 1127
Reputation: 64740
Everything seems to be only speaking about converting directly ByteString into a final type.
What makes "a finaly type" special? Can Value
be "final type"?
I think you're talking about the FromJSON class, which Value
is already an instance.
You mention how Haskell can be frustrating and you've been searching for a function. Perhaps what you need isn't just a solution (decode
as mentioned by @WillemVanOnsem) but also learning how to search.
How to Search
First, look at the documentation of type you want and its instances If you're at all familiar with the library you should recognize the important instances of ToJSON and FromJSON, which yield what you desire.
If the instances do not suffice then use Hoogle as Chris commented. In this case you could tell hoogle to look just at Aeson and the type of the function you'd like: +aeson ByteString -> Value
.
Upvotes: 2
Reputation: 476594
Value
is an instance of FromJSON
, so you can make use of decode :: FromJSON a => ByteString -> Maybe a
:
Prelude Data.Aeson> decode "{\"menu\": {\"id\": \"file\", \"value\": \"File\", \"popup\": {\"menuitem\": [1,4,2,5]}}}" :: Maybe Value
Just (Object (fromList [("menu",Object (fromList [("popup",Object (fromList [("menuitem",Array [Number 1.0,Number 4.0,Number 2.0,Number 5.0])])),("value",String "File"),("id",String "file")]))]))
So in fact there is nothing to define at all, you can use decode
to decode to a Value
as well. You however probably should specify the siganture to make that clear, so decode "4" :: Maybe Value
for example.
The return type of decode is a Maybe Value
, since it is not said that the ByteString
you provided is a valid JSON stream. If you are absolutely sure it is valid JSON, you can use fromJust :: Maybe a -> a
. But it is probably better to implement some sort of fallback mechanism.
Upvotes: 5