I want to parse an API response into a data type using servant-client, servant-xml and xmlbf libraries.
This is an example API response
<GoodreadsResponse>
<Request>
<authentication>true</authentication>
<key>api_key</key>
<method>search_index</method>
</Request>
<search>
<query>Ender's Game</query>
<results-start>1</results-start>
<results-end>20</results-end>
</search>
</GoodreadsResponse>
and this is the data type I want to parse it into
data GoodreadsRequest =
GoodreadsRequest { authentication :: Text
, key :: Text
, method :: Text
}
data GoodreadsSearch =
GoodreadsSearch { query :: Text
, resultsStart :: Int
, resultsEnd :: Int
}
data GoodreadsResponse =
GoodreadsResponse { goodreadsRequest :: GoodreadsRequest
, goodreadsSearch :: GoodreadsSearch
}
This is the servant API type I want to use it with
type API
= "search" :> "index.xml" :> QueryParam "key" Key :> QueryParam "q" Query :> Get '[XML] GoodreadsResponse
which constructs an endpoint like this
https://www.goodreads.com/search/index.xml?key=api_key&q=Ender%27s+Game
and after writing the rest of the scaffolding code (clientM, baseURL, client environment, etc), the error I get is
No instance for (FromXml GoodreadsResponse) arising from a use of 'client'
Writing
instance FromXml GoodreadsResponse where
fromXml = undefined
suppresses the error so I think I'm on the right track, but I don't know how to go about writing the parser.
Edit: Result from a different end-point that contains a list of 'works'
<GoodreadsResponse>
<Request>
<authentication>true</authentication>
<key>api_key</key>
<method>search_index</method>
</Request>
<search>
<query>Ender's Game</query>
<results-start>1</results-start>
<results-end>20</results-end>
<results>
<work>
<id type="integer">2422333</id>
<average_rating>4.30</average_rating>
<best_book type="Book">
<id type="integer">375802</id>
<title>Ender's Game (Ender's Saga, #1)</title>
</best_book>
</work>
<work>
<id type="integer">4892733</id>
<average_rating>2.49</average_rating>
<best_book type="Book">
<id type="integer">44687</id>
<title>Enchanters' End Game (The Belgariad, #5)</title>
</best_book>
</work>
<work>
<id type="integer">293823</id>
<average_rating>2.30</average_rating>
<best_book type="Book">
<id type="integer">6393082</id>
<title>Ender's Game, Volume 1: Battle School (Ender's Saga)</title>
</best_book>
</work>
</results>
</search>
</GoodreadsResponse>
to be parsed into
data GoodreadsResponse =
GoodreadsResponse { goodreadsRequest :: GoodreadsRequest
, goodreadsSearch :: GoodreadsSearch
}
data GoodreadsRequest =
GoodreadsRequest { authentication :: Text
, key :: Text
, method :: Text
}
data GoodreadsSearch =
GoodreadsSearch { query :: Text
, resultsStart :: Int
, resultsEnd :: Int
, results :: GoodreadsSearchResults
}
data GoodreadsSearchResults = GooreadsSearchResults { works :: [Work] }
data Work = Work { workID :: Int
, workAverageRating :: Double
, workBestMatchingBook :: Book
}
data Book = Book { bookID :: Int
, bookTitle :: Text
}
<id type="integer">, what else cantypeever be? Can you add examples? - Joseph Sible-Reinstate Monicatypecan be eitherintegerorBook. - atisbest_bookto be ignored? - Joseph Sible-Reinstate Monica