{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
module Servant.Hateoas.Example where
import Servant.Hateoas
import Servant
import Data.Aeson
import GHC.Generics
data User = User { User -> Int
usrId :: Int, User -> Int
addressId :: Int, User -> Double
income :: Double }
deriving stock ((forall x. User -> Rep User x)
-> (forall x. Rep User x -> User) -> Generic User
forall x. Rep User x -> User
forall x. User -> Rep User x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. User -> Rep User x
from :: forall x. User -> Rep User x
$cto :: forall x. Rep User x -> User
to :: forall x. Rep User x -> User
Generic, Int -> User -> ShowS
[User] -> ShowS
User -> String
(Int -> User -> ShowS)
-> (User -> String) -> ([User] -> ShowS) -> Show User
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> User -> ShowS
showsPrec :: Int -> User -> ShowS
$cshow :: User -> String
show :: User -> String
$cshowList :: [User] -> ShowS
showList :: [User] -> ShowS
Show, User -> User -> Bool
(User -> User -> Bool) -> (User -> User -> Bool) -> Eq User
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: User -> User -> Bool
== :: User -> User -> Bool
$c/= :: User -> User -> Bool
/= :: User -> User -> Bool
Eq, Eq User
Eq User =>
(User -> User -> Ordering)
-> (User -> User -> Bool)
-> (User -> User -> Bool)
-> (User -> User -> Bool)
-> (User -> User -> Bool)
-> (User -> User -> User)
-> (User -> User -> User)
-> Ord User
User -> User -> Bool
User -> User -> Ordering
User -> User -> User
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: User -> User -> Ordering
compare :: User -> User -> Ordering
$c< :: User -> User -> Bool
< :: User -> User -> Bool
$c<= :: User -> User -> Bool
<= :: User -> User -> Bool
$c> :: User -> User -> Bool
> :: User -> User -> Bool
$c>= :: User -> User -> Bool
>= :: User -> User -> Bool
$cmax :: User -> User -> User
max :: User -> User -> User
$cmin :: User -> User -> User
min :: User -> User -> User
Ord)
deriving anyclass ([User] -> Value
[User] -> Encoding
User -> Bool
User -> Value
User -> Encoding
(User -> Value)
-> (User -> Encoding)
-> ([User] -> Value)
-> ([User] -> Encoding)
-> (User -> Bool)
-> ToJSON User
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: User -> Value
toJSON :: User -> Value
$ctoEncoding :: User -> Encoding
toEncoding :: User -> Encoding
$ctoJSONList :: [User] -> Value
toJSONList :: [User] -> Value
$ctoEncodingList :: [User] -> Encoding
toEncodingList :: [User] -> Encoding
$comitField :: User -> Bool
omitField :: User -> Bool
ToJSON)
data Address = Address { Address -> Int
addrId :: Int, Address -> String
street :: String, Address -> String
city :: String }
deriving stock ((forall x. Address -> Rep Address x)
-> (forall x. Rep Address x -> Address) -> Generic Address
forall x. Rep Address x -> Address
forall x. Address -> Rep Address x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Address -> Rep Address x
from :: forall x. Address -> Rep Address x
$cto :: forall x. Rep Address x -> Address
to :: forall x. Rep Address x -> Address
Generic, Int -> Address -> ShowS
[Address] -> ShowS
Address -> String
(Int -> Address -> ShowS)
-> (Address -> String) -> ([Address] -> ShowS) -> Show Address
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Address -> ShowS
showsPrec :: Int -> Address -> ShowS
$cshow :: Address -> String
show :: Address -> String
$cshowList :: [Address] -> ShowS
showList :: [Address] -> ShowS
Show, Address -> Address -> Bool
(Address -> Address -> Bool)
-> (Address -> Address -> Bool) -> Eq Address
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Address -> Address -> Bool
== :: Address -> Address -> Bool
$c/= :: Address -> Address -> Bool
/= :: Address -> Address -> Bool
Eq, Eq Address
Eq Address =>
(Address -> Address -> Ordering)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Bool)
-> (Address -> Address -> Address)
-> (Address -> Address -> Address)
-> Ord Address
Address -> Address -> Bool
Address -> Address -> Ordering
Address -> Address -> Address
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Address -> Address -> Ordering
compare :: Address -> Address -> Ordering
$c< :: Address -> Address -> Bool
< :: Address -> Address -> Bool
$c<= :: Address -> Address -> Bool
<= :: Address -> Address -> Bool
$c> :: Address -> Address -> Bool
> :: Address -> Address -> Bool
$c>= :: Address -> Address -> Bool
>= :: Address -> Address -> Bool
$cmax :: Address -> Address -> Address
max :: Address -> Address -> Address
$cmin :: Address -> Address -> Address
min :: Address -> Address -> Address
Ord)
deriving anyclass ([Address] -> Value
[Address] -> Encoding
Address -> Bool
Address -> Value
Address -> Encoding
(Address -> Value)
-> (Address -> Encoding)
-> ([Address] -> Value)
-> ([Address] -> Encoding)
-> (Address -> Bool)
-> ToJSON Address
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: Address -> Value
toJSON :: Address -> Value
$ctoEncoding :: Address -> Encoding
toEncoding :: Address -> Encoding
$ctoJSONList :: [Address] -> Value
toJSONList :: [Address] -> Value
$ctoEncodingList :: [Address] -> Encoding
toEncodingList :: [Address] -> Encoding
$comitField :: Address -> Bool
omitField :: Address -> Bool
ToJSON, ToResource res)
instance Resource res => ToResource res User where
toResource :: Proxy res -> User -> res User
toResource Proxy res
_ User
usr = (String, ResourceLink) -> res User -> res User
forall a. (String, ResourceLink) -> res a -> res a
forall (res :: * -> *) a.
Resource res =>
(String, ResourceLink) -> res a -> res a
addRel (String
"address", Link -> ResourceLink
CompleteLink (Link -> ResourceLink) -> Link -> ResourceLink
forall a b. (a -> b) -> a -> b
$ Int -> Link
mkAddrLink (Int -> Link) -> Int -> Link
forall a b. (a -> b) -> a -> b
$ User -> Int
addressId User
usr) (res User -> res User) -> res User -> res User
forall a b. (a -> b) -> a -> b
$ User -> res User
forall a. a -> res a
forall (res :: * -> *) a. Resource res => a -> res a
wrap User
usr
where
mkAddrLink :: MkLink AddressGetOne Link
mkAddrLink = Proxy AddressGetOne
-> Proxy AddressGetOne -> MkLink AddressGetOne Link
forall endpoint api.
(IsElem endpoint api, HasLink endpoint) =>
Proxy api -> Proxy endpoint -> MkLink endpoint Link
safeLink (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @AddressGetOne) (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @AddressGetOne)
type Api = UserApi :<|> AddressApi
type UserApi = UserGetOne :<|> UserGetAll :<|> UserGetQuery
type UserGetOne = "api" :> "user" :> Capture "id" Int :> Get '[JSON] User
type UserGetAll = "api" :> "user" :> Get '[JSON] [User]
type UserGetQuery = "api" :> "user" :> "querying" :> QueryParam "addrId" Int :> QueryParam "income" Double :> Get '[JSON] User
type AddressApi = AddressGetOne
type AddressGetOne = "api" :> "address" :> Capture "id" Int :> Get '[JSON] Address
instance HasHandler UserGetOne where
getHandler :: forall (m :: * -> *).
MonadIO m =>
Proxy m -> Proxy UserGetOne -> ServerT UserGetOne m
getHandler Proxy m
_ Proxy UserGetOne
_ = \Int
uId -> User -> m User
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (User -> m User) -> User -> m User
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Double -> User
User Int
uId Int
0 Double
0
instance HasHandler UserGetAll where
getHandler :: forall (m :: * -> *).
MonadIO m =>
Proxy m -> Proxy UserGetAll -> ServerT UserGetAll m
getHandler Proxy m
_ Proxy UserGetAll
_ = [User] -> m [User]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Int -> Int -> Double -> User
User Int
1 Int
1 Double
1000, Int -> Int -> Double -> User
User Int
2 Int
2 Double
2000, Int -> Int -> Double -> User
User Int
42 Int
3 Double
3000]
instance HasHandler UserGetQuery where
getHandler :: forall (m :: * -> *).
MonadIO m =>
Proxy m -> Proxy UserGetQuery -> ServerT UserGetQuery m
getHandler Proxy m
_ Proxy UserGetQuery
_ = \Maybe Int
mAddrId Maybe Double
mIncome -> User -> m User
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (User -> m User) -> User -> m User
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Double -> User
User Int
42 (Int -> (Int -> Int) -> Maybe Int -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 Int -> Int
forall a. a -> a
id Maybe Int
mAddrId) (Double -> (Double -> Double) -> Maybe Double -> Double
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Double
0 Double -> Double
forall a. a -> a
id Maybe Double
mIncome)
instance HasHandler AddressGetOne where
getHandler :: forall (m :: * -> *).
MonadIO m =>
Proxy m -> Proxy AddressGetOne -> ServerT AddressGetOne m
getHandler Proxy m
_ Proxy AddressGetOne
_ = \Int
aId -> Address -> m Address
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Address -> m Address) -> Address -> m Address
forall a b. (a -> b) -> a -> b
$ Int -> String -> String -> Address
Address Int
aId String
"Foo St" String
"BarBaz"
layerServer :: ServerT
(Resourcify
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
GetIntermediate,
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
GetIntermediate,
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
GetIntermediate,
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
GetIntermediate,
'Layer '[] '[Sym "api", Sym "api", Sym "api"] GetIntermediate]
(HAL JSON))
Handler
layerServer = Proxy Handler
-> Proxy (HAL JSON)
-> Proxy
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
GetIntermediate,
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
GetIntermediate,
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
GetIntermediate,
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
GetIntermediate,
'Layer '[] '[Sym "api", Sym "api", Sym "api"] GetIntermediate]
-> ServerT
(Resourcify
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
GetIntermediate,
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
GetIntermediate,
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
GetIntermediate,
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
GetIntermediate,
'Layer '[] '[Sym "api", Sym "api", Sym "api"] GetIntermediate]
(HAL JSON))
Handler
forall {k} (api :: k) (m :: * -> *) ct.
(HasResourceServer api m ct, MonadIO m) =>
Proxy m -> Proxy ct -> Proxy api -> ServerT (Resourcify api ct) m
getResourceServer (forall {k} (t :: k). Proxy t
forall (t :: * -> *). Proxy t
Proxy @Handler) (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(HAL JSON)) (forall (t :: [Layer]). Proxy t
forall {k} (t :: k). Proxy t
Proxy @(MkLayers Api))
layerApp :: Application
layerApp :: Application
layerApp = Proxy
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[]
'[Sym "api", Sym "api", Sym "api"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate))]
-> Server
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[]
'[Sym "api", Sym "api", Sym "api"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate))]
-> Application
forall {k} (api :: k).
HasServer api '[] =>
Proxy api -> Server api -> Application
serve (forall (t :: [Layer]). Proxy t
forall {k} (t :: k). Proxy t
Proxy @((Resourcify (MkLayers Api)) (HAL JSON))) Handler (HALResource Intermediate)
:<|> (Handler (HALResource Intermediate)
:<|> (Handler (HALResource Intermediate)
:<|> (Handler (HALResource Intermediate)
:<|> (Handler (HALResource Intermediate)
:<|> Tagged Handler EmptyServer))))
Server
'[ 'Layer
'[Sym "api", Sym "address"]
'[Capture' '[] "id" Int]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user", Sym "querying"]
'[QueryParam' '[Optional, Strict] "addrId" Int,
QueryParam' '[Optional, Strict] "income" Double]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api", Sym "user"]
'[Capture' '[] "id" Int, Sym "querying"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[Sym "api"]
'[Sym "user", Sym "user", Sym "address"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate)),
'Layer
'[]
'[Sym "api", Sym "api", Sym "api"]
(Verb 'GET 200 '[HAL JSON] (HALResource Intermediate))]
layerServer
apiServer :: ServerT (Resourcify Api (HAL JSON)) Handler
apiServer = Proxy Handler
-> Proxy (HAL JSON)
-> Proxy Api
-> ServerT (Resourcify Api (HAL JSON)) Handler
forall {k} (api :: k) (m :: * -> *) ct.
(HasResourceServer api m ct, MonadIO m) =>
Proxy m -> Proxy ct -> Proxy api -> ServerT (Resourcify api ct) m
getResourceServer (forall {k} (t :: k). Proxy t
forall (t :: * -> *). Proxy t
Proxy @Handler) (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(HAL JSON)) (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @Api)
apiApp :: Application
apiApp :: Application
apiApp = Proxy
((("api"
:> ("user"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))
:<|> (("api"
:> ("user" :> Verb 'GET 200 '[HAL JSON] (HALResource [User])))
:<|> ("api"
:> ("user"
:> ("querying"
:> (QueryParam' '[Optional, Strict] "addrId" Int
:> (QueryParam' '[Optional, Strict] "income" Double
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))))))
:<|> ("api"
:> ("address"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource Address)))))
-> Server
((("api"
:> ("user"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))
:<|> (("api"
:> ("user" :> Verb 'GET 200 '[HAL JSON] (HALResource [User])))
:<|> ("api"
:> ("user"
:> ("querying"
:> (QueryParam' '[Optional, Strict] "addrId" Int
:> (QueryParam' '[Optional, Strict] "income" Double
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))))))
:<|> ("api"
:> ("address"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource Address)))))
-> Application
forall {k} (api :: k).
HasServer api '[] =>
Proxy api -> Server api -> Application
serve (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @((Resourcify Api) (HAL JSON))) ((Int -> Handler (HALResource User))
:<|> (Handler (HALResource [User])
:<|> (Maybe Int -> Maybe Double -> Handler (HALResource User))))
:<|> (Int -> Handler (HALResource Address))
Server
((("api"
:> ("user"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))
:<|> (("api"
:> ("user" :> Verb 'GET 200 '[HAL JSON] (HALResource [User])))
:<|> ("api"
:> ("user"
:> ("querying"
:> (QueryParam' '[Optional, Strict] "addrId" Int
:> (QueryParam' '[Optional, Strict] "income" Double
:> Verb 'GET 200 '[HAL JSON] (HALResource User))))))))
:<|> ("api"
:> ("address"
:> (Capture' '[] "id" Int
:> Verb 'GET 200 '[HAL JSON] (HALResource Address)))))
apiServer