This morning I was following along with this interesting tutorial on using Servant to build a simple API server.
At the end of the tutorial, the author suggests adding a Blog type, so I figured I would give it a shot, but I got stuck trying to implement and serialize a foreign key relationship that extends upon the logic in the tutorial (perhaps an important disclosure here: I'm new to both Servant and Persistent).
Here are my Persistent definitions (I added the Post
):
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
User
name String
email String
deriving Show
Post
title String
user UserId
summary String
content String
deriving Show
|]
The tutorial builds a separate Person
data type for the Servant API, so I added one called Article
as well:
-- API Data Types
data Person = Person
{ name :: String
, email :: String
} deriving (Eq, Show, Generic)
data Article = Article
{ title :: String
, author :: Person
, summary :: String
, content :: String
} deriving (Eq, Show, Generic)
instance ToJSON Person
instance FromJSON Person
instance ToJSON Article
instance FromJSON Article
userToPerson :: User -> Person
userToPerson User{..} = Person { name = userName, email = userEmail }
Now, however, when I attempt to create a function that turns a Post
into an Article
, I get stuck trying to deal with the User
foreign key:
postToArticle :: Post -> Article
postToArticle Post{..} = Article {
title = postTitle
, author = userToPerson postUser -- this fails
, summary = postSummary
, content = postContent
}
I tried a number of things, but the above seemed to be close to the direction I'd like to go in. It doesn't compile, however, due to the following the error:
Couldn't match expected type ‘User’
with actual type ‘persistent-2.2.2:Database.Persist.Class.PersistEntity.Key
User’
In the first argument of ‘userToPerson’, namely ‘postUser’
In the ‘author’ field of a record
Ultimately, I'm not really sure what a PersistEntity.Key User
really is and my errant googling has not gotten me much closer.
How do I deal with this foreign-key relationship?
Working Version
Edited with an answer thanks to haoformayor
postToArticle :: MonadIO m => Post -> SqlPersistT m (Maybe Article)
postToArticle Post{..} = do
authorMaybe <- selectFirst [UserId ==. postUser] []
return $ case authorMaybe of
Just (Entity _ author) ->
Just Article {
title = postTitle
, author = userToPerson author
, summary = postSummary
, content = postContent
}
Nothing ->
Nothing