I have an API which returns JSON results in the following form:
{
"data": [1, 2, 3]
}
The data
field can be the encoding of two distinct records which are shown below:
newtype ResultsTypeA = ResultsTypeA [ResultTypeA]
newtype ResultsTypeB = ResultsTypeB [ResultTypeB]
When I query this API from Haskell, I know in advance whether I'm dealing with a ResultsTypeA
or a ResultsTypeB
because I'm explicitly asking for it in the query.
The part where I'm struggling is with the Aeson ToJSON
and FromJSON
instances. Since both result types A
and B
are ultimately lists of Int
, I can't use pattern matcher in FromJSON
, because I could only match a [Int]
in both cases.
This is why I thought of doing the following:
newType ApiResponse a =
ApiResponse {
data :: a
}
newtype ResultsTypeA = ResultsTypeA [ResultTypeA]
newtype ResultsTypeB = ResultsTypeB [ResultTypeB]
However I can't get my head around how to write the ToJSON
and FromJSON
instances for the above, because now ApiResponse
has a type parameter, and nowhere in Aeson docs seem to be a place where it is explained how to derive these instances with a type parameter involved.
Another alternative, avoiding a type parameter, would be the following:
newtype Results =
ResultsTypeA [ResultTypeA]
| ResultsTypeB [ResultTypeB]
newtype ApiResponse =
ApiResponse {
data :: Results
}
In this case the ToJSON
is straightforward:
instance ToJSON ApiResponse where
toJSON = genericToJSON $ defaultOptions
But the FromJSON
gets us back to the problem of not being able to decide between result types A
and B
...
It is also possible that I'm doing it wrong entirely and there is a third option I wouldn't see.
- how would the
FromJSON
/ToJSON
instances look like with a type parameter onApiResponse
? - is there a better alternative completely different from anything exposed above to address this?