diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,17 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [PVP versioning](https://pvp.haskell.org/).
 
+## v0.3.4 _(2024-12-30)_
+
+### Added
+- Added class `HasTemplateLink` for fully templated links to endpoints
+- Added combinator `data Title (sym :: Symbol)` for human-readable titles of resources
+
+### Changed
+- Class `HasRelationLink` now returns complete links instead of partially templated ones
+- Replaced all usages of `Link` with `RelationLink`, allowing more flexibility when gathering information about the resource the link refers to
+- Extended the rendering of `HALResource` by props `type` (Content-Type) and `title`
+
 ## v0.3.3 _(2024-12-28)_
 
 ### Added
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -61,18 +61,19 @@
 
 -- add a link to the address-resource with the relation "address" for the user-resource
 instance Resource res => ToResource res User where
-  toResource _ usr = addRel ("address", CompleteLink $ mkAddrLink $ addressId usr) $ wrap usr
+  toResource _ ct usr = addRel ("address", mkAddrLink $ addressId usr) $ wrap usr
     where
-      mkAddrLink = safeLink (Proxy @AddressGetOne) (Proxy @AddressGetOne)
+      mkAddrLink = toRelationLink $ resourcifyProxy (Proxy @AddressGetOne) ct
 ```
 
 Further we define our API as usual:
 ```haskell
 type Api = UserApi :<|> AddressApi
 
-type UserApi = UserGetOne :<|> UserGetAll :<|> UserGetAllCool
-type UserGetOne     = "api" :> "user" :> Capture "id" Int :> Get '[JSON] User
-type UserGetAll     = "api" :> "user" :> Get '[JSON] [User]
+type UserApi = UserGetOne :<|> UserGetAll :<|> UserGetQuery
+type UserGetOne    = "api" :> "user" :> Title "The user with the given id" :> Capture "id" Int :> Get '[JSON] User
+type UserGetAll    = "api" :> "user" :> Get '[JSON] [User]
+type UserGetQuery  = "api" :> "user" :> "query" :> QueryParam "addrId" Int :> QueryParam "income" Double :> Get '[JSON] User
 
 type AddressApi = AddressGetOne
 type AddressGetOne = "api" :> "address" :> Capture "id" Int :> Get '[JSON] Address
@@ -89,9 +90,11 @@
 This is nothing but the usual servant-server implementation, just that the implementation is not floating around in the source code and instead is bound to a class instance.
 ```haskell
 instance HasHandler UserGetOne where
-  getHandler _ _ = \uId -> return $ User uId 1 1000
+  getHandler _ _ = \uId -> return $ User uId 0 0
 instance HasHandler UserGetAll where
   getHandler _ _ = return [User 1 1 1000, User 2 2 2000, User 42 3 3000]
+instance HasHandler UserGetQuery where
+  getHandler _ _ = \mAddrId mIncome -> return $ User 42 (maybe 0 id mAddrId) (maybe 0 id mIncome)
 instance HasHandler AddressGetOne where
   getHandler _ _ = \aId -> return $ Address aId "Foo St" "BarBaz"
 ```
@@ -103,6 +106,50 @@
 ```
 
 For now `apiServer` and `layerServer` exist in isolation, but the goal is to merge them into one.
+
+When we now run the `layerServer` and request `GET http://host:port/api/user/query`, we get:
+```json
+{
+    "_embedded": {},
+    "_links": {
+        "addrId": {
+            "href": "/api/user/query{?addrId}",
+            "templated": true,
+            "type": "application/hal+json"
+        },
+        "income": {
+            "href": "/api/user/query{?income}",
+            "templated": true,
+            "type": "application/hal+json"
+        },
+        "self": {
+            "href": "/api/user/query",
+            "type": "application/hal+json"
+        }
+    }
+}
+```
+
+Similar for `userServer` and `GET http://host:port/api/user/42`:
+```json
+{
+    "_embedded": {},
+    "_links": {
+        "address": {
+            "href": "/api/address/0",
+            "type": "application/hal+json"
+        },
+        "self": {
+            "href": "/api/user/42",
+            "title": "The user with the given id",
+            "type": "application/hal+json"
+        }
+    },
+    "addressId": 0,
+    "income": 0,
+    "usrId": 42
+}
+```
 
 The complete example can be found [here](https://github.com/bruderj15/servant-hateoas/blob/main/src/Servant/Hateoas/Example.hs).
 
diff --git a/servant-hateoas.cabal b/servant-hateoas.cabal
--- a/servant-hateoas.cabal
+++ b/servant-hateoas.cabal
@@ -1,6 +1,6 @@
 cabal-version:           3.0
 name:                    servant-hateoas
-version:                 0.3.3
+version:                 0.3.4
 synopsis:                HATEOAS extension for servant
 description:             Create Resource-Representations for your types and make your API HATEOAS-compliant.
   Automatically derive a HATEOAS-API and server-implementation from your API or straight up define a HATEOAS-API yourself.
@@ -41,6 +41,7 @@
                        , Servant.Hateoas.Layer.Build
                        , Servant.Hateoas.Layer.Merge
                        , Servant.Hateoas.ContentType.HAL
+                       , Servant.Hateoas.Combinator.Title
                        , Servant.Hateoas.Internal.Sym
                        , Servant.Hateoas.Internal.Polyvariadic
 
diff --git a/src/Servant/Hateoas.hs b/src/Servant/Hateoas.hs
--- a/src/Servant/Hateoas.hs
+++ b/src/Servant/Hateoas.hs
@@ -1,5 +1,6 @@
 module Servant.Hateoas
-( module Servant.Hateoas.ContentType.HAL
+( module Servant.Hateoas.Combinator.Title
+, module Servant.Hateoas.ContentType.HAL
 , module Servant.Hateoas.ResourceServer
 , module Servant.Hateoas.RelationLink
 , module Servant.Hateoas.HasHandler
@@ -7,6 +8,7 @@
 , module Servant.Hateoas.Layer
 ) where
 
+import Servant.Hateoas.Combinator.Title
 import Servant.Hateoas.ContentType.HAL (HAL, HALResource)
 import Servant.Hateoas.ResourceServer
 import Servant.Hateoas.RelationLink
diff --git a/src/Servant/Hateoas/Combinator/Title.hs b/src/Servant/Hateoas/Combinator/Title.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Hateoas/Combinator/Title.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+module Servant.Hateoas.Combinator.Title where
+
+import Servant
+import Servant.Hateoas.HasHandler
+import Servant.Hateoas.RelationLink
+import Servant.Hateoas.Internal.Polyvariadic
+import Data.String (fromString)
+import Control.Applicative ((<|>))
+import GHC.TypeLits
+
+-- | Combinator similar to 'Summary' and 'Description' but for the human readable title of the resource a 'RelationLink' refers to.
+data Title (sym :: Symbol)
+
+instance HasLink b => HasLink (Title sym :> b) where
+  type MkLink (Title sym :> b) link = MkLink b link
+  toLink f _ = toLink f (Proxy @b)
+
+instance HasServer api ctx => HasServer (Title desc :> api) ctx where
+  type ServerT (Title desc :> api) m = ServerT api m
+  route _ = route (Proxy @api)
+  hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy @api) pc nt s
+
+instance HasHandler api => HasHandler (Title desc :> api) where
+  getHandler m _ = getHandler m (Proxy @api)
+
+instance (KnownSymbol title, HasTemplatedLink api) => HasTemplatedLink (Title title :> api) where
+  toTemplatedLink _  = (\l -> l { _title = _title l <|> Just title }) $ toTemplatedLink (Proxy @api)
+    where
+      title = fromString $ symbolVal (Proxy @title)
+
+instance (KnownSymbol title, RightLink api) => HasRelationLink (Title title :> api) where
+  toRelationLink _  = (\l -> l { _title = _title l <|> Just title }) ... toRelationLink (Proxy @api)
+    where
+      title = fromString $ symbolVal (Proxy @title)
diff --git a/src/Servant/Hateoas/ContentType/Collection.hs b/src/Servant/Hateoas/ContentType/Collection.hs
--- a/src/Servant/Hateoas/ContentType/Collection.hs
+++ b/src/Servant/Hateoas/ContentType/Collection.hs
@@ -8,6 +8,7 @@
 where
 
 import Servant.Hateoas.Resource
+import Servant.Hateoas.RelationLink
 import Servant.API.ContentTypes
 import qualified Network.HTTP.Media as M
 import Servant.Links
@@ -28,7 +29,7 @@
 data CollectionResource a = CollectionResource
   { href  :: Maybe URI                   -- ^ Link to the collection
   , items :: [CollectionItem a]          -- ^ All items in the collection
-  , rels  :: [(String, ResourceLink)]    -- ^ Pairs @(rel, link)@ for relations
+  , rels  :: [(String, RelationLink)]    -- ^ Pairs @(rel, link)@ for relations
   } deriving (Show, Generic, Functor)
 
 instance Semigroup (CollectionResource a) where
@@ -40,7 +41,7 @@
 -- | A single item inside a 'CollectionResource'.
 data CollectionItem a = CollectionItem
   { item :: a                             -- ^ Wrapped item
-  , itemLinks :: [(String, ResourceLink)]         -- ^ Links for the wrapped item
+  , itemLinks :: [(String, RelationLink)]         -- ^ Links for the wrapped item
   } deriving (Show, Generic, Functor)
 
 instance Resource CollectionResource where
@@ -57,7 +58,7 @@
 instance ToJSON (CollectionResource a) => MimeRender (Collection JSON) (CollectionResource a) where
   mimeRender _ = encode
 
-collectionLinks :: [(String, ResourceLink)] -> Value
+collectionLinks :: [(String, RelationLink)] -> Value
 collectionLinks = Array . Foldable.foldl' (\xs (rel, l) -> pure (object ["name" .= rel, "value" .= l]) <> xs) mempty
 
 -- TODO: I dont like this at all
diff --git a/src/Servant/Hateoas/ContentType/HAL.hs b/src/Servant/Hateoas/ContentType/HAL.hs
--- a/src/Servant/Hateoas/ContentType/HAL.hs
+++ b/src/Servant/Hateoas/ContentType/HAL.hs
@@ -19,6 +19,7 @@
 import Data.Kind
 import Data.Aeson
 import Data.Aeson.KeyMap (singleton)
+import qualified Data.Text as Text
 import GHC.Exts
 import GHC.Generics
 
@@ -32,7 +33,7 @@
 -- | HAL-resource representation.
 data HALResource a = HALResource
   { resource :: a                                       -- ^ Wrapped resource
-  , rels     :: [(String, ResourceLink)]                -- ^ Pairs @(rel, link)@ for hypermedia relations
+  , rels     :: [(String, RelationLink)]                -- ^ Pairs @(rel, link)@ for hypermedia relations
   , embedded :: [(String, SomeF HALResource ToJSON)]    -- ^ Pairs @(rel, resource)@ for embedded resources
   } deriving (Generic, Functor)
 
@@ -46,9 +47,12 @@
 instance ToJSON (HALResource a) => MimeRender (HAL JSON) (HALResource a) where
   mimeRender _ = encode
 
-renderHalLink :: ResourceLink -> Value
-renderHalLink (CompleteLink l) = let uri = linkURI l in object ["href" .= uri { uriPath = "/" <> uriPath uri }]
-renderHalLink (TemplateLink l) = object $ ["href" .= l {_path  = "/" <> _path l } ] <> if _templated l then ["templated" .= True] else []
+renderHalLink :: RelationLink -> Value
+renderHalLink l = object $
+  [ "href" .= getHref l
+  , "type" .= Text.intercalate "|" (fromString . show <$> _contentTypes l)
+  ] <> if _templated l then ["templated" .= True] else []
+    <> maybe mempty (\t -> ["title" .= t]) (_title l)
 
 instance {-# OVERLAPPABLE #-} ToJSON a => ToJSON (HALResource a) where
   toJSON (HALResource res ls es) = Object $ (singleton "_links" ls') <> (singleton "_embedded" es') <> (case toJSON res of Object kvm -> kvm ; _ -> mempty)
diff --git a/src/Servant/Hateoas/Example.hs b/src/Servant/Hateoas/Example.hs
--- a/src/Servant/Hateoas/Example.hs
+++ b/src/Servant/Hateoas/Example.hs
@@ -17,16 +17,16 @@
   deriving anyclass (ToJSON, ToResource res)
 
 instance Resource res => ToResource res User where
-  toResource _ usr = addRel ("address", CompleteLink $ mkAddrLink $ addressId usr) $ wrap usr
+  toResource _ ct usr = addRel ("address", mkAddrLink $ addressId usr) $ wrap usr
     where
-      mkAddrLink = safeLink (Proxy @AddressGetOne) (Proxy @AddressGetOne)
+      mkAddrLink = toRelationLink $ resourcifyProxy (Proxy @AddressGetOne) ct
 
 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 UserGetOne    = "api" :> "user" :> Title "The user with the given id" :> Capture "id" Int :> Get '[JSON] User
+type UserGetAll    = "api" :> "user" :> Get '[JSON] [User]
+type UserGetQuery  = "api" :> "user" :> "query" :>QueryParam "addrId" Int :> QueryParam "income" Double :> Get '[JSON] User
 
 type AddressApi = AddressGetOne
 type AddressGetOne = "api" :> "address" :> Capture "id" Int :> Get '[JSON] Address
diff --git a/src/Servant/Hateoas/Internal/Sym.hs b/src/Servant/Hateoas/Internal/Sym.hs
--- a/src/Servant/Hateoas/Internal/Sym.hs
+++ b/src/Servant/Hateoas/Internal/Sym.hs
@@ -25,7 +25,10 @@
   type MkLink (Sym sym :> api) link = MkLink (sym :> api) link
   toLink f _ = toLink f (Proxy @(sym :> api))
 
-instance (HasRelationLink api, KnownSymbol sym) => HasRelationLink (Sym sym :> api) where
+instance (HasTemplatedLink api, KnownSymbol sym) => HasTemplatedLink (Sym sym :> api) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @(sym :> api))
+
+instance (KnownSymbol sym, HasRelationLink (sym :> api), HasLink api) => HasRelationLink (Sym sym :> api) where
   toRelationLink _ = toRelationLink (Proxy @(sym :> api))
 
 instance (HasHandler api, KnownSymbol sym) => HasHandler (Sym sym :> api) where
diff --git a/src/Servant/Hateoas/Layer/Build.hs b/src/Servant/Hateoas/Layer/Build.hs
--- a/src/Servant/Hateoas/Layer/Build.hs
+++ b/src/Servant/Hateoas/Layer/Build.hs
@@ -12,7 +12,6 @@
 
 import Servant
 import Servant.API.ContentTypes
-import Servant.Hateoas.Resource
 import Servant.Hateoas.RelationLink
 import Servant.Hateoas.Layer.Type
 import Servant.Hateoas.Internal.Sym
@@ -27,179 +26,155 @@
   ReplaceHandler (a -> b)    replacement = a -> ReplaceHandler b replacement
   ReplaceHandler _           replacement = replacement
 
--- | Create all 'ResourceLink's to a 'Layer's 'RelativeChildren'.
+-- | Create all 'RelationLink's to a 'Layer's 'RelativeChildren'.
 type BuildLayerLinks :: Layer -> (Type -> Type) -> Constraint
 class BuildLayerLinks l m where
-  buildLayerLinks :: MonadIO m => Proxy l -> Proxy m -> ReplaceHandler (ServerT l m) [(String, ResourceLink)]
+  buildLayerLinks :: MonadIO m => Proxy l -> Proxy m -> ReplaceHandler (ServerT l m) [(String, RelationLink)]
 
 instance
   ( api ~ MkPrefix apiCs verb
-  , HasLink api, IsElem api api
-  , mkSelf ~ MkLink api Link
+  , HasRelationLink api
+  , mkSelf ~ MkLink api RelationLink
   , PolyvariadicComp mkSelf (IsFun mkSelf)
-  , Return mkSelf (IsFun mkSelf) ~ Link
-  , Replace mkSelf [(String, ResourceLink)] (IsFun mkSelf) ~ ReplaceHandler (ServerT api m) [(String, ResourceLink)]
+  , Return mkSelf (IsFun mkSelf) ~ RelationLink
+  , Replace mkSelf [(String, RelationLink)] (IsFun mkSelf) ~ ReplaceHandler (ServerT api m) [(String, RelationLink)]
   ) => BuildLayerLinks ('Layer apiCs '[] verb) m where
-  buildLayerLinks _ _ = (pure @[] . ("self", ) . CompleteLink) ... mkSelf
+  buildLayerLinks _ _ = (pure @[] . ("self", )) ... mkSelf
     where
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
 
 instance
   ( c ~ MkPrefix (apiCs ++ '[Sym sym]) verb
-  , HasLink c, IsElem c c
-  , mkLink ~ MkLink c Link
+  , HasRelationLink c
+  , mkLink ~ MkLink c RelationLink
   , KnownSymbol sym
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT (MkPrefix apiCs verb) m) [(String, ResourceLink)])
+  , buildLinksFun ~ (ReplaceHandler (ServerT (MkPrefix apiCs verb) m) [(String, RelationLink)])
   , PolyvariadicComp2 mkLink buildLinksFun (IsFun mkLink)
-  , Return2 mkLink buildLinksFun (IsFun mkLink) ~ (Link, [(String, ResourceLink)])
-  , Replace2 mkLink buildLinksFun [(String, ResourceLink)] (IsFun mkLink) ~ buildLinksFun
+  , Return2 mkLink buildLinksFun (IsFun mkLink) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 mkLink buildLinksFun [(String, RelationLink)] (IsFun mkLink) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (Sym sym ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(l, ls) -> (symbolVal (Proxy @sym), CompleteLink l) : ls) mkLink mkLinks
+  buildLayerLinks _ m = pcomp2 (\(l, ls) -> (symbolVal (Proxy @sym), l) : ls) mkLink mkLinks
     where
-      mkLink = safeLink (Proxy @c) (Proxy @c)
+      mkLink = toRelationLink (Proxy @c)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[Capture' mods sym x] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[Capture' mods sym x] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (Capture' mods sym x ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[Capture' mods sym x] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _path = _path rl `appendPath` _path child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[Capture' mods sym x] verb))
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[CaptureAll sym x] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[CaptureAll sym x] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (CaptureAll sym x ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[CaptureAll sym x] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _path = _path rl `appendPath` _path child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[CaptureAll sym x] verb))
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[QueryParam' mods sym x] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[QueryParam' mods sym x] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (QueryParam' mods sym x ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[QueryParam' mods sym x] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _params = _params rl ++ _params child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[QueryParam' mods sym x] verb))
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[QueryParams sym x] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[QueryParams sym x] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (QueryParams sym x ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[QueryParams sym x] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _params = _params rl ++ _params child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[QueryParams sym x] verb))
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[DeepQuery sym x] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[DeepQuery sym x] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (DeepQuery sym x ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[DeepQuery sym x] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _params = _params rl ++ _params child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[DeepQuery sym x] verb))
 
 instance
   ( verb ~ Verb method status cts a
   , AllMime cts, ReflectMethod method
   , api ~ MkPrefix apiCs verb
+  , HasRelationLink api
   , KnownSymbol sym
-  , HasRelationLink (MkPrefix '[QueryFlag sym] verb)
-  , IsElem api api, HasLink api
+  , HasTemplatedLink (MkPrefix '[QueryFlag sym] verb)
   , BuildLayerLinks ('Layer apiCs cs verb) m
-  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, ResourceLink)])
-  , PolyvariadicComp2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun)
-  , Return2 (MkLink api Link) buildLinksFun (IsFun buildLinksFun) ~ (Link, [(String, ResourceLink)])
-  , Replace2 (MkLink api Link) buildLinksFun [(String, ResourceLink)] (IsFun buildLinksFun) ~ buildLinksFun
+  , buildLinksFun ~ (ReplaceHandler (ServerT api m) [(String, RelationLink)])
+  , PolyvariadicComp2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun)
+  , Return2 (MkLink api RelationLink) buildLinksFun (IsFun buildLinksFun) ~ (RelationLink, [(String, RelationLink)])
+  , Replace2 (MkLink api RelationLink) buildLinksFun [(String, RelationLink)] (IsFun buildLinksFun) ~ buildLinksFun
   ) => BuildLayerLinks ('Layer apiCs (QueryFlag sym ': cs) verb) m where
-  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, mkTemplatedNext self) : ls) mkSelf mkLinks
+  buildLayerLinks _ m = pcomp2 (\(self, ls) -> (relName, self <<< child) : ls) mkSelf mkLinks
     where
       relName = symbolVal (Proxy @sym)
-      mkSelf = safeLink (Proxy @api) (Proxy @api)
+      mkSelf = toRelationLink (Proxy @api)
       mkLinks = buildLayerLinks (Proxy @('Layer apiCs cs verb)) m
-      child = toRelationLink (Proxy @(MkPrefix '[QueryFlag sym] verb))
-      mkTemplatedNext = TemplateLink
-        . (\rl -> rl { _params = _params rl ++ _params child, _templated = True })
-        . fromURI (allMime $ Proxy @cts) (reflectStdMethod (Proxy @method))
-        . linkURI
+      child = toTemplatedLink (Proxy @(MkPrefix '[QueryFlag sym] verb))
diff --git a/src/Servant/Hateoas/Layer/Type.hs b/src/Servant/Hateoas/Layer/Type.hs
--- a/src/Servant/Hateoas/Layer/Type.hs
+++ b/src/Servant/Hateoas/Layer/Type.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE DerivingStrategies #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE DeriveAnyClass #-}
 
 module Servant.Hateoas.Layer.Type
 (
@@ -105,8 +106,6 @@
 -- | A response type for a 'Layer' that does not contain any data.
 newtype Intermediate = Intermediate ()
   deriving newtype (Show, Eq, Ord, ToJSON)
+  deriving anyclass (ToResource res)
 
 type GetIntermediate = Get '[] Intermediate
-
-instance Resource res => ToResource res Intermediate where
-  toResource _ _ = wrap $ Intermediate ()
diff --git a/src/Servant/Hateoas/RelationLink.hs b/src/Servant/Hateoas/RelationLink.hs
--- a/src/Servant/Hateoas/RelationLink.hs
+++ b/src/Servant/Hateoas/RelationLink.hs
@@ -10,14 +10,24 @@
   RelationParam(..),
 
   -- *** Creation
+  fromLink,
   fromURI,
 
   -- *** Operations
+  (<<<),
+  getHref,
+  getPath,
+  getParams,
+  prependSeg,
+  prependSegs,
+  addParam,
+  addParams,
   mkPlaceHolder,
-  appendPath,
 
   -- ** Class
+  HasTemplatedLink(..),
   HasRelationLink(..),
+  RightLink,
 
   -- * Utility
   -- ** ReflectStdMethod
@@ -25,59 +35,131 @@
 )
 where
 
-import Prelude hiding (dropWhile, break)
+import Prelude hiding (drop, dropWhile, break)
 import Servant
 import Servant.API.ContentTypes (AllMime(..))
 import Servant.API.Modifiers (FoldRequired)
-import Network.URI (unEscapeString)
+import Servant.Hateoas.Internal.Polyvariadic
+import Network.URI (unEscapeString, pathSegments)
 import Network.HTTP.Media (MediaType)
 import Network.HTTP.Types (parseMethod, Method)
+import Data.Foldable (foldl')
+import Data.Maybe
 import Data.String (fromString)
 import Data.Aeson
-import Data.Text (Text, intercalate, dropWhile, split, break)
+import Data.Text (Text, intercalate, dropWhile, split, break, drop, isPrefixOf, isSuffixOf)
 import Data.Singletons.Bool
+import Control.Applicative ((<|>))
 import GHC.TypeLits
 
 -- | Link data-type for hypermedia-links in HATEOAS with potentially templated URIs.
 data RelationLink = RelationLink
-  { _path         :: Text
+  { _segs         :: [Text]
   , _params       :: [RelationParam]
+  , _fragment     :: Maybe Text
   , _templated    :: Bool
   , _method       :: StdMethod
   , _contentTypes :: [MediaType]
   , _summary      :: Maybe Text
   , _description  :: Maybe Text
+  , _title        :: Maybe Text
   } deriving (Show, Eq)
 
 -- | Parameter data-type for hypermedia-links in HATEOAS.
 data RelationParam = RelationParam
   { _name        :: Text
   , _required    :: Bool
+  , _value       :: Maybe Text
   } deriving (Show, Eq)
 
--- | Create a placeholder for a URI template parameter.
+-- | Shifting append-operator for 'RelationLink'.
+--
+-- This operator can be seen as a monoidal append for 'RelationLink' with a right-bias for meta information
+-- e.g. '_method', '_contentTypes', '_summary' and '_description'.
+(<<<) :: RelationLink -> RelationLink -> RelationLink
+l1 <<< l2 =
+  l1 { _segs         = _segs         l1  <> _segs        l2
+     , _params       = _params       l1  <> _params      l2
+     , _fragment     = _fragment     l1 <|> _fragment    l2
+     , _templated    = _templated    l1  || _templated   l2
+     , _method       = _method       l2
+     , _contentTypes = _contentTypes l2
+     , _summary      = _summary      l2 <|> _summary     l1
+     , _description  = _description  l2 <|> _description l1
+     }
+
+-- | Get the hypermedia-reference of a 'RelationLink'.
+getHref :: RelationLink -> Text
+getHref l = getPath l <> getParams l <> maybe "" (\f -> "#" <> f) (_fragment l)
+
+-- | Get the path of a 'RelationLink' as in 'getHref'.
+getPath :: RelationLink -> Text
+getPath = ("/" <>) .  intercalate "/" . _segs
+
+-- | Get the parameters of a 'RelationLink' as in 'getHref'.
+getParams :: RelationLink -> Text
+getParams link =
+     (if filledParams == [] then "" else "?" <> intercalate "&" (fmap (\(k,v) -> k <> "=" <> v) filledParams))
+  <> (if templatedParams == [] then "" else "{?" <> intercalate "," templatedParams <> "}")
+  where
+    (filledParams, templatedParams) =
+      foldl'
+        (\(fs, ts) l -> case _value l of Nothing -> (fs, _name l : ts) ; Just v -> ((_name l, v) : fs, ts))
+        ([], []) $
+        _params link
+
+-- | Prepend a path segment to a 'RelationLink'.
+--
+-- Takes care of potential templating.
+prependSeg :: Text -> RelationLink -> RelationLink
+prependSeg seg l
+  | "{" `isPrefixOf` seg && "}" `isSuffixOf` seg = l { _segs = seg : _segs l, _templated = True }
+  | otherwise = l { _segs = seg : _segs l }
+
+-- | Prepend path segments to a 'RelationLink'.
+--
+-- Takes care of potential templating.
+prependSegs :: [Text] -> RelationLink -> RelationLink
+prependSegs segs l
+  | any (\seg -> "{" `isPrefixOf` seg && "}" `isSuffixOf` seg) segs = l { _segs = segs <> _segs l, _templated = True }
+  | otherwise                                                       = l { _segs = segs <> _segs l }
+
+-- | Add a parameter to a 'RelationLink'.
+--
+-- Takes care of potential templating.
+addParam :: RelationParam -> RelationLink -> RelationLink
+addParam p l = l { _params = p : _params l, _templated = _templated l || isNothing (_value p) }
+
+-- | Add parameters to a 'RelationLink'.
+--
+-- Takes care of potential templating.
+addParams :: [RelationParam] -> RelationLink -> RelationLink
+addParams ps l = l { _params = ps <> _params l, _templated = _templated l || any (isNothing . _value) ps }
+
+-- | Create a placeholder for a template path segment.
 mkPlaceHolder :: Text -> Text
 mkPlaceHolder s = "{" <> s <> "}"
 
--- | Append a path to a URI.
-appendPath :: Text -> Text -> Text
-appendPath l "" = l
-appendPath l r = l <> "/" <> r
+-- | Creates a 'RelationLink' from a 'Link'.
+fromLink :: [MediaType] -> StdMethod -> Link -> RelationLink
+fromLink cts m = fromURI cts m . linkURI
 
 -- | Creates a 'RelationLink' from an 'URI'.
 fromURI :: [MediaType] -> StdMethod -> URI -> RelationLink
-fromURI cts m (URI _ _ path query _) = RelationLink
-  { _path = fromString path
+fromURI cts m uri@(URI _ _ _ query frag) = RelationLink
+  { _segs = fromString <$> pathSegments uri
   , _params = params
+  , _fragment = if frag == "" then Nothing else Just (fromString frag)
   , _templated = False
   , _method = m
   , _contentTypes = cts
   , _summary = Nothing
   , _description = Nothing
+  , _title = Nothing
   }
   where
     params = filter ((/= "") . _name)
-      $ fmap (\kv -> RelationParam (fst $ break (== '=') kv) False)
+      $ fmap (\kv -> let (k, drop 1 -> v) = break (== '=') kv in RelationParam k False $ if v == "" then Nothing else Just v)
       $ split (== '&')
       $ dropWhile (== '?')
       $ fromString
@@ -92,148 +174,287 @@
 unsafeMethodToStdMethod (parseMethod -> Left  m) = error $ "Cannot convert " <> show m <> " to StdMethod"
 
 instance ToJSON RelationLink where
-  toJSON (RelationLink path params templated _ _ _ _) = String $
-    if not (null params) && templated
-    then path <> "{?" <> intercalate "," (_name <$> params) <> "}"
-    else path
+  toJSON = String . getHref
 
--- | Class for creating a 'RelationLink' to an API.
-class HasRelationLink endpoint where
-  toRelationLink :: Proxy endpoint -> RelationLink
+-- | Class for creating a templated 'RelationLink' to an endpoint.
+class HasTemplatedLink endpoint where
+  toTemplatedLink :: Proxy endpoint -> RelationLink
 
-instance HasRelationLink b => HasRelationLink (EmptyAPI :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (EmptyAPI :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance (KnownSymbol sym, HasRelationLink b) => HasRelationLink ((sym :: Symbol) :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _path = prefix `appendPath` _path rl }
+instance (KnownSymbol sym, HasTemplatedLink b) => HasTemplatedLink ((sym :: Symbol) :> b) where
+  toTemplatedLink _ = prependSeg prefix $ toTemplatedLink (Proxy @b)
     where
       prefix = fromString $ symbolVal (Proxy @sym)
 
-instance (KnownSymbol sym, HasRelationLink b) => HasRelationLink (Capture' mods sym a :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _path = prefix `appendPath` _path rl, _templated = True }
+instance (KnownSymbol sym, HasTemplatedLink b) => HasTemplatedLink (Capture' mods sym a :> b) where
+  toTemplatedLink _ = prependSeg prefix $ toTemplatedLink (Proxy @b)
     where
       prefix = mkPlaceHolder $ fromString $ symbolVal (Proxy @sym)
 
-instance (KnownSymbol sym, HasRelationLink b) => HasRelationLink (CaptureAll sym a :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _path = prefix `appendPath` _path rl, _templated = True }
+instance (KnownSymbol sym, HasTemplatedLink b) => HasTemplatedLink (CaptureAll sym a :> b) where
+  toTemplatedLink _ = prependSeg prefix $ toTemplatedLink (Proxy @b)
     where
       prefix = mkPlaceHolder $ fromString $ symbolVal (Proxy @sym)
 
-instance HasRelationLink b => HasRelationLink (Header' mods sym a :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (Header' mods sym a :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (HttpVersion :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (HttpVersion :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance (HasRelationLink b, KnownSymbol sym, SBoolI (FoldRequired mods)) => HasRelationLink (QueryParam' mods sym a :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
+instance (HasTemplatedLink b, KnownSymbol sym, SBoolI (FoldRequired mods)) => HasTemplatedLink (QueryParam' mods sym a :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
     where
       param = RelationParam
         { _name = fromString $ symbolVal (Proxy @sym)
         , _required = fromSBool $ sbool @(FoldRequired mods)
+        , _value = Nothing
         }
 
-instance (HasRelationLink b, KnownSymbol sym) => HasRelationLink (QueryParams sym a :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
+instance (HasTemplatedLink b, KnownSymbol sym) => HasTemplatedLink (QueryParams sym a :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
     where
       param = RelationParam
         { _name = fromString $ symbolVal (Proxy @sym)
         , _required = False
+        , _value = Nothing
         }
 
-instance (HasRelationLink b, KnownSymbol sym) => HasRelationLink (QueryFlag sym :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
+instance (HasTemplatedLink b, KnownSymbol sym) => HasTemplatedLink (QueryFlag sym :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
     where
       param = RelationParam
         { _name = fromString $ symbolVal (Proxy @sym)
         , _required = False
+        , _value = Nothing
         }
 
-instance HasRelationLink b => HasRelationLink (QueryString :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (QueryString :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance (HasRelationLink b, KnownSymbol sym) => HasRelationLink (DeepQuery sym a :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
+instance (HasTemplatedLink b, KnownSymbol sym) => HasTemplatedLink (DeepQuery sym a :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _params = param : _params rl, _templated = True }
     where
       param = RelationParam
         { _name = fromString $ symbolVal (Proxy @sym)
         , _required = False
+        , _value = Nothing
         }
 
-instance HasRelationLink b => HasRelationLink (Fragment a :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (Fragment a :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (ReqBody' mods cts a :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (ReqBody' mods cts a :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (RemoteHost :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (RemoteHost :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (IsSecure :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (IsSecure :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (Vault :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (Vault :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (WithNamedContext name subs sub :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (WithNamedContext name subs sub :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance HasRelationLink b => HasRelationLink (WithResource res :> b) where
-  toRelationLink _ = toRelationLink (Proxy @b)
+instance HasTemplatedLink b => HasTemplatedLink (WithResource res :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
 
-instance (ReflectMethod m, AllMime cts) => HasRelationLink (Verb m s cts a) where
-  toRelationLink _ = RelationLink
-    { _path = mempty
+instance (ReflectMethod m, AllMime cts) => HasTemplatedLink (Verb m s cts a) where
+  toTemplatedLink _ = RelationLink
+    { _segs = mempty
     , _params = []
+    , _fragment = Nothing
     , _templated = False
+    , _contentTypes = allMime (Proxy @cts)
     , _method = reflectStdMethod (Proxy @m)
     , _summary = Nothing
     , _description = Nothing
+    , _title = Nothing
+    }
+
+instance ReflectMethod m => HasTemplatedLink (NoContentVerb m) where
+  toTemplatedLink _ = RelationLink
+    { _segs = mempty
+    , _params = []
+    , _fragment = Nothing
+    , _templated = False
+    , _contentTypes = mempty
+    , _method = reflectStdMethod (Proxy @m)
+    , _summary = Nothing
+    , _description = Nothing
+    , _title = Nothing
+    }
+
+instance (ReflectMethod m, AllMime cts) => HasTemplatedLink (UVerb m cts as) where
+  toTemplatedLink _ = RelationLink
+    { _segs = mempty
+    , _params = []
+    , _fragment = Nothing
+    , _templated = False
     , _contentTypes = allMime (Proxy @cts)
+    , _method = reflectStdMethod (Proxy @m)
+    , _summary = Nothing
+    , _description = Nothing
+    , _title = Nothing
     }
 
-instance ReflectMethod m => HasRelationLink (NoContentVerb m) where
-  toRelationLink _ = RelationLink
-    { _path = mempty
+instance (ReflectMethod m, Accept ct) => HasTemplatedLink (Stream m s f ct a) where
+  toTemplatedLink _ = RelationLink
+    { _segs = mempty
     , _params = []
+    , _fragment = Nothing
     , _templated = False
+    , _contentTypes = pure $ contentType (Proxy @ct)
     , _method = reflectStdMethod (Proxy @m)
     , _summary = Nothing
     , _description = Nothing
-    , _contentTypes = mempty
+    , _title = Nothing
     }
 
-instance (ReflectMethod m, AllMime cts) => HasRelationLink (UVerb m cts as) where
+instance HasTemplatedLink b => HasTemplatedLink (BasicAuth realm userData :> b) where
+  toTemplatedLink _ = toTemplatedLink (Proxy @b)
+
+instance (KnownSymbol sym, HasTemplatedLink b) => HasTemplatedLink (Description sym :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _description = _description rl <|> Just descr }
+    where
+      descr = fromString $ symbolVal (Proxy @sym)
+
+instance (KnownSymbol sym, HasTemplatedLink b) => HasTemplatedLink (Summary sym :> b) where
+  toTemplatedLink _ = let rl = toTemplatedLink (Proxy @b) in rl { _summary = _summary rl <|> Just summary }
+    where
+      summary = fromString $ symbolVal (Proxy @sym)
+
+-- | Class for creating a 'RelationLink' to an endpoint.
+--
+-- This is highly similar to 'HasLink' but it also gathers HATEOAS meta-information for the resource a link refers to.
+class HasLink endpoint => HasRelationLink endpoint where
+  toRelationLink :: Proxy endpoint -> MkLink endpoint RelationLink
+
+-- | Convenience alias-constraint for right-hand sides of @a ':>' b@ where b is some function producing a 'RelationLink'.
+type RightLink b =
+  ( HasRelationLink b
+  , PolyvariadicComp (MkLink b RelationLink) (IsFun (MkLink b RelationLink))
+  , Return (MkLink b RelationLink) (IsFun (MkLink b RelationLink)) ~ RelationLink
+  , Replace (MkLink b RelationLink) RelationLink (IsFun (MkLink b RelationLink)) ~ MkLink b RelationLink
+  )
+
+instance (AllMime cts, ReflectMethod m) => HasRelationLink (Verb m s cts a) where
   toRelationLink _ = RelationLink
-    { _path = mempty
+    { _segs = mempty
     , _params = []
+    , _fragment = Nothing
     , _templated = False
+    , _contentTypes = allMime (Proxy @cts)
     , _method = reflectStdMethod (Proxy @m)
     , _summary = Nothing
     , _description = Nothing
+    , _title = Nothing
+    }
+
+instance (AllMime cts, ReflectMethod m) => HasRelationLink (UVerb m cts as) where
+  toRelationLink _ = RelationLink
+    { _segs = mempty
+    , _params = []
+    , _fragment = Nothing
+    , _templated = False
     , _contentTypes = allMime (Proxy @cts)
+    , _method = reflectStdMethod (Proxy @m)
+    , _summary = Nothing
+    , _description = Nothing
+    , _title = Nothing
     }
 
-instance (ReflectMethod m, Accept ct) => HasRelationLink (Stream m s f ct a) where
+instance ReflectMethod m => HasRelationLink (NoContentVerb m) where
   toRelationLink _ = RelationLink
-    { _path = mempty
+    { _segs = mempty
     , _params = []
+    , _fragment = Nothing
     , _templated = False
+    , _contentTypes = mempty
     , _method = reflectStdMethod (Proxy @m)
     , _summary = Nothing
     , _description = Nothing
+    , _title = Nothing
+    }
+
+instance (ReflectMethod m, Accept ct) => HasRelationLink (Stream m s f ct a) where
+  toRelationLink _ = RelationLink
+    { _segs = mempty
+    , _params = []
+    , _fragment = Nothing
+    , _templated = False
     , _contentTypes = pure $ contentType (Proxy @ct)
+    , _method = reflectStdMethod (Proxy @m)
+    , _summary = Nothing
+    , _description = Nothing
+    , _title = Nothing
     }
 
+instance (KnownSymbol sym, RightLink b) => HasRelationLink ((sym :: Symbol) :> b) where
+  toRelationLink _ = prependSeg seg ... toRelationLink (Proxy @b)
+    where
+      seg = fromString $ symbolVal (Proxy @sym)
+
+instance (KnownSymbol sym, RightLink b) => HasRelationLink (Summary sym :> b) where
+  toRelationLink _ = (\rl -> rl { _summary = _summary rl <|> Just summary }) ... toRelationLink (Proxy @b)
+    where
+      summary = fromString $ symbolVal (Proxy @sym)
+
+instance (KnownSymbol sym, RightLink b) => HasRelationLink (Description sym :> b) where
+  toRelationLink _ = (\rl -> rl { _description = _description rl <|> Just descr }) ... toRelationLink (Proxy @b)
+    where
+      descr = fromString $ symbolVal (Proxy @sym)
+
+instance HasRelationLink b => HasRelationLink (HttpVersion :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
 instance HasRelationLink b => HasRelationLink (BasicAuth realm userData :> b) where
   toRelationLink _ = toRelationLink (Proxy @b)
 
-instance (KnownSymbol sym, HasRelationLink b) => HasRelationLink (Description sym :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _description = Just descr }
+instance (KnownSymbol sym, RightLink b, ToHttpApiData a) => HasRelationLink (Capture' mods sym a :> b) where
+  toRelationLink _ x = prependSeg (toUrlPiece x) ... toRelationLink (Proxy @b)
+
+instance (KnownSymbol sym, RightLink b, ToHttpApiData a) => HasRelationLink (CaptureAll sym a :> b) where
+  toRelationLink _ xs = prependSegs (toUrlPiece <$> xs) ... toRelationLink (Proxy @b)
+
+instance (RightLink b, ToHttpApiData a) => HasRelationLink (Fragment a :> b) where
+  toRelationLink _ x = (\l -> l { _fragment = Just $ toQueryParam x }) ... toRelationLink (Proxy @b)
+
+instance HasRelationLink b => HasRelationLink (Header' mods sym a :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
+instance HasRelationLink b => HasRelationLink (IsSecure :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
+instance (KnownSymbol sym, RightLink b) => HasRelationLink (QueryFlag sym :> b) where
+  toRelationLink _ False = addParam (RelationParam (fromString $ symbolVal $ Proxy @sym) False (Just "false")) ... toRelationLink (Proxy @b)
+  toRelationLink _ True  = addParam (RelationParam (fromString $ symbolVal $ Proxy @sym) False (Just "true")) ... toRelationLink (Proxy @b)
+
+instance (KnownSymbol sym, ToHttpApiData a, RightLink b, SBoolI (FoldRequired mods)) => HasRelationLink (QueryParam' mods sym a :> b) where
+  toRelationLink _ mv = addParam param ... toRelationLink (Proxy @b)
     where
-      descr = fromString $ symbolVal (Proxy @sym)
+      param = case sbool :: SBool (FoldRequired mods) of
+        STrue  -> RelationParam (fromString $ symbolVal $ Proxy @sym) True    (Just $ toQueryParam mv)
+        SFalse -> RelationParam (fromString $ symbolVal $ Proxy @sym) False $ toQueryParam <$> mv
 
-instance (KnownSymbol sym, HasRelationLink b) => HasRelationLink (Summary sym :> b) where
-  toRelationLink _ = let rl = toRelationLink (Proxy @b) in rl { _summary = Just summary }
+instance (KnownSymbol sym, RightLink b, ToHttpApiData a) => HasRelationLink (QueryParams sym a :> b) where
+  toRelationLink _ xs = addParams params ... toRelationLink (Proxy @b)
     where
-      summary = fromString $ symbolVal (Proxy @sym)
+      params = (\x -> RelationParam (fromString $ symbolVal $ Proxy @sym) False (Just $ toQueryParam x)) <$> xs
+
+instance RightLink b => HasRelationLink (RemoteHost :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
+instance RightLink b => HasRelationLink (ReqBody' mods cts a :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
+instance RightLink b => HasRelationLink (WithResource res :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
+
+instance RightLink b => HasRelationLink (Vault :> b) where
+  toRelationLink _ = toRelationLink (Proxy @b)
diff --git a/src/Servant/Hateoas/Resource.hs b/src/Servant/Hateoas/Resource.hs
--- a/src/Servant/Hateoas/Resource.hs
+++ b/src/Servant/Hateoas/Resource.hs
@@ -3,9 +3,6 @@
 
 module Servant.Hateoas.Resource
 (
-  -- * ResourceLink
-  ResourceLink(..),
-
   -- * Resource
   -- ** MkResource
   MkResource,
@@ -30,27 +27,16 @@
 -- | Type family computing the Resource-Type belonging to this Content-Type.
 type family MkResource ct :: (Type -> Type)
 
--- | Type for Hypermedia-Links.
---
-data ResourceLink =
-    CompleteLink Link               -- ^ A complete 'Link' with all information.
-  | TemplateLink RelationLink       -- ^ A 'RelationLink' that can be used as a template for URIs.
-  deriving (Show)
-
-instance ToJSON ResourceLink where
-  toJSON (CompleteLink l) = let uri = linkURI l in toJSON $ uri { uriPath = "/" <> uriPath uri }
-  toJSON (TemplateLink l) = toJSON $ l { _path = "/" <> _path l }
-
 -- | Class for resources that carry Hypermedia-Relations.
 class Resource res where
   -- | Wrap a value into a 'Resource'.
   wrap :: a -> res a
 
   -- | Add a hypermedia relation @(rel, link)@ to a 'Resource'.
-  addRel :: (String, ResourceLink) -> res a -> res a
+  addRel :: (String, RelationLink) -> res a -> res a
 
 -- | Add the self-relation to a 'Resource'.
-addSelfRel :: Resource res => ResourceLink -> res a -> res a
+addSelfRel :: Resource res => RelationLink -> res a -> res a
 addSelfRel l = addRel ("self", l)
 
 -- | Class for 'Resource's that can embed other resources.
@@ -69,8 +55,8 @@
 -- Therefore you can derive an instance for this class.
 class ToResource res a where
   -- | Describes how a value @a@ can be converted to a 'Resource'.
-  toResource :: Proxy res -> a -> res a
-  default toResource :: Resource res => Proxy res -> a -> res a
-  toResource _ = wrap
+  toResource :: (res ~ MkResource ct, Accept ct) => Proxy res -> Proxy ct -> a -> res a
+  default toResource :: (res ~ MkResource ct, Resource res) => Proxy res -> Proxy ct -> a -> res a
+  toResource _ _ = wrap
 
 instance Resource res => ToResource res [a]
diff --git a/src/Servant/Hateoas/ResourceServer.hs b/src/Servant/Hateoas/ResourceServer.hs
--- a/src/Servant/Hateoas/ResourceServer.hs
+++ b/src/Servant/Hateoas/ResourceServer.hs
@@ -7,6 +7,7 @@
 
   -- * Type-Families
   Resourcify,
+  resourcifyProxy,
   ResourcifyServer
 )
 where
@@ -15,6 +16,7 @@
 import Servant.Hateoas.Layer
 import Servant.Hateoas.Resource
 import Servant.Hateoas.HasHandler
+import Servant.Hateoas.RelationLink
 import Servant.Hateoas.Internal.Polyvariadic
 import Data.Kind
 import Control.Monad.IO.Class
@@ -30,6 +32,10 @@
   Resourcify (x:xs)          ct = Resourcify x ct : Resourcify xs ct
   Resourcify a               _  = a
 
+-- | A proxy function for 'Resourcify'.
+resourcifyProxy :: forall api ct. Proxy api -> Proxy ct -> Proxy (Resourcify api ct)
+resourcifyProxy _ _ = Proxy @(Resourcify api ct)
+
 -- | Turns a 'ServerT' into a resourceful 'ServerT' by replacing the result type @m a@ of the function @server@ with @m (res a)@ where
 -- @res := 'MkResource' ct@.
 --
@@ -57,19 +63,20 @@
 instance {-# OVERLAPPABLE #-}
   ( server ~ ServerT api m
   , ServerT (Resourcify api ct) m ~ ResourcifyServer server ct m
-  , mkLink ~ MkLink api Link
+  , mkLink ~ MkLink (Resourcify api ct) RelationLink
+  , Accept ct
   , res ~ MkResource ct
   , Resource res
   , ToResource res a
   , HasHandler api
-  , HasLink api, IsElem api api
+  , HasRelationLink (Resourcify api ct)
   , PolyvariadicComp2 server mkLink (IsFun server)
-  , Return2 server mkLink (IsFun server) ~ (m a, Link)
+  , Return2 server mkLink (IsFun server) ~ (m a, RelationLink)
   , Replace2 server mkLink (m (res a)) (IsFun mkLink) ~ ResourcifyServer server ct m
   ) => HasResourceServer (api :: Type) m ct where
-  getResourceServer m _ api = pcomp2 ((\(ma, self) -> (addSelfRel (CompleteLink self) . toResource (Proxy @res)) <$> ma)) (getHandler m api) mkSelf
+  getResourceServer m _ api = pcomp2 ((\(ma, self) -> (addSelfRel self . toResource (Proxy @res) (Proxy @ct)) <$> ma)) (getHandler m api) mkSelf
     where
-      mkSelf = safeLink api api
+      mkSelf = toRelationLink (Proxy @(Resourcify api ct))
 
 instance
   ( api ~ LayerApi l
@@ -77,11 +84,11 @@
   , ServerT (Resourcify l ct) m ~ ResourcifyServer (ServerT l m) ct m
   , rServer ~ ResourcifyServer (ServerT l m) ct m
   , res ~ MkResource ct
-  , buildFun ~ ReplaceHandler rServer [(String, ResourceLink)]
+  , buildFun ~ ReplaceHandler rServer [(String, RelationLink)]
   , Resource res
   , BuildLayerLinks (Resourcify l ct) m
   , PolyvariadicComp buildFun (IsFun buildFun)
-  , Return buildFun (IsFun buildFun) ~ [(String, ResourceLink)]
+  , Return buildFun (IsFun buildFun) ~ [(String, RelationLink)]
   , Replace buildFun (m (res Intermediate)) (IsFun buildFun) ~ rServer
   ) => HasResourceServer l m ct where
   getResourceServer m _ _ = (return @m . foldr addRel (wrap @res $ Intermediate ())) ... buildLayerLinks (Proxy @(Resourcify l ct)) m
