我正在寻找解决一个问题,即我从 HTTP 调用构建一些数据,然后基于该数据进行另一个 HTTP 调用,并使用来自第二个调用的信息来丰富原始数据。
我的代码通过 wreq 将 Spotify 最近播放的 API 调用 (JSON) 作为 ByteString 并返回我完全形成的“RecentlyPlayed”数据类型。
但是,为了在 Spotify API 中获取曲目的流派,需要对其艺术家端点进行第二次 HTTP 调用,我不太确定如何修改我的 Track 数据类型以在其中添加“流派”字段我稍后会填充,我也不确定以后如何实际填充它,显然我需要遍历我的原始数据结构,拉出艺术家 ID,调用新服务器 - 但我不确定如何添加这个原始数据类型的附加数据。
{-# LANGUAGE OverloadedStrings #-}
module Types.RecentlyPlayed where
import qualified Data.ByteString.Lazy as L
import qualified Data.Vector as V
import Data.Aeson
import Data.Either
data Artist = Artist {
id :: String
, href :: String
, artistName :: String
} deriving (Show)
data Track = Track {
playedAt :: String
, externalUrls :: String
, name :: String
, artists :: [Artist]
, explicit :: Bool
} deriving (Show)
data Tracks = Tracks {
tracks :: [Track]
} deriving (Show)
data RecentlyPlayed = RecentlyPlayed {
recentlyPlayed :: Tracks
, next :: String
} deriving (Show)
instance FromJSON RecentlyPlayed where
parseJSON = withObject "items" $ \recentlyPlayed -> RecentlyPlayed
<$> recentlyPlayed .: "items"
<*> recentlyPlayed .: "next"
instance FromJSON Tracks where
parseJSON = withArray "items" $ \items -> Tracks
<$> mapM parseJSON (V.toList items)
instance FromJSON Track where
parseJSON = withObject "tracks" $ \tracks -> Track
<$> tracks .: "played_at"
<*> (tracks .: "track" >>= (.: "album") >>= (.: "external_urls") >>= (.: "spotify"))
<*> (tracks .: "track" >>= (.: "name"))
<*> (tracks .: "track" >>= (.: "artists"))
<*> (tracks .: "track" >>= (.: "explicit"))
instance FromJSON Artist where
parseJSON = withObject "artists" $ \artists -> Artist
<$> artists .: "id"
<*> artists .: "href"
<*> artists .: "name"
marshallRecentlyPlayedData :: L.ByteString -> Either String RecentlyPlayed
marshallRecentlyPlayedData recentlyPlayedTracks = eitherDecode recentlyPlayedTracks
(https://github.com/imjacobclark/Recify/blob/master/src/Types/RecentlyPlayed.hs)
这对于单个 API 调用非常有效,它的用法可以在这里看到:
recentlyPlayedTrackData <- liftIO $ (getCurrentUsersRecentlyPlayedTracks (textToByteString . getAccessToken . AccessToken $ accessTokenFileData))
let maybeMarshalledRecentlyPlayed = (marshallRecentlyPlayedData recentlyPlayedTrackData)
(https://github.com/imjacobclark/Recify/blob/master/src/Recify.hs#L53-L55)
{-# LANGUAGE OverloadedStrings #-}
module Clients.Spotify.RecentlyPlayed where
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as B
import qualified Network.Wreq as W
import System.Environment
import Control.Monad.IO.Class
import Control.Lens
recentlyPlayerUri = "https://api.spotify.com/v1/me/player/recently-played"
getCurrentUsersRecentlyPlayedTracks :: B.ByteString -> IO L.ByteString
getCurrentUsersRecentlyPlayedTracks accessToken = do
let options = W.defaults & W.header "Authorization" .~ [(B.pack "Bearer ") <> accessToken]
text <- liftIO $ (W.getWith options recentlyPlayerUri)
return $ text ^. W.responseBody
(https://github.com/imjacobclark/Recify/blob/master/src/Clients/Spotify/RecentlyPlayed.hs)
我希望能够调用第一个 API,构造我的数据类型,调用第二个 API,然后使用第二个 HTTP 调用返回的数据丰富第一个数据类型。