Merge pull request #23 from haskell-servant/canonical-types
Add the `Canonicalize` type family to reduce API types to their canonical forms before proceeding in the other packages
This commit is contained in:
commit
3311cbd901
3 changed files with 42 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
||||||
0.3
|
0.3
|
||||||
---
|
---
|
||||||
|
* Add a `Canonicalize` type family that distributes all `:>`s inside `:<|>`s to get to the canonical type of an API -- which is then used in all other packages to avoid weird handler types in *servant-server*.
|
||||||
* Multiple content-type/accept support for all the relevant combinators
|
* Multiple content-type/accept support for all the relevant combinators
|
||||||
* Provide *JSON*, *PlainText*, *OctetStream* and *FormUrlEncoded* content types out of the box
|
* Provide *JSON*, *PlainText*, *OctetStream* and *FormUrlEncoded* content types out of the box
|
||||||
* Type-safe link generation to API endpoints
|
* Type-safe link generation to API endpoints
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
module Servant.API (
|
module Servant.API (
|
||||||
|
|
||||||
-- * Combinators
|
-- * Combinators
|
||||||
|
@ -43,11 +46,16 @@ module Servant.API (
|
||||||
module Servant.Common.Text,
|
module Servant.Common.Text,
|
||||||
-- | Classes and instances for types that can be converted to and from @Text@
|
-- | Classes and instances for types that can be converted to and from @Text@
|
||||||
|
|
||||||
|
-- * Canonicalizing (flattening) API types
|
||||||
|
Canonicalize,
|
||||||
|
canonicalize,
|
||||||
|
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
module Servant.Utils.Links,
|
module Servant.Utils.Links,
|
||||||
-- | Type-safe internal URIs
|
-- | Type-safe internal URIs
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Data.Proxy (Proxy(..))
|
||||||
import Servant.Common.Text (FromText(..), ToText(..))
|
import Servant.Common.Text (FromText(..), ToText(..))
|
||||||
import Servant.API.Alternative ((:<|>) (..))
|
import Servant.API.Alternative ((:<|>) (..))
|
||||||
import Servant.API.Capture (Capture)
|
import Servant.API.Capture (Capture)
|
||||||
|
@ -69,3 +77,34 @@ import Servant.API.ReqBody (ReqBody)
|
||||||
import Servant.API.Sub ((:>))
|
import Servant.API.Sub ((:>))
|
||||||
import Servant.Utils.Links (HasLink (..), IsElem, IsElem',
|
import Servant.Utils.Links (HasLink (..), IsElem, IsElem',
|
||||||
URI (..), safeLink)
|
URI (..), safeLink)
|
||||||
|
|
||||||
|
-- | Turn an API type into its canonical form.
|
||||||
|
--
|
||||||
|
-- The canonical form of an API type is basically the all-flattened form
|
||||||
|
-- of the original type. More formally, it takes a type as input and hands you
|
||||||
|
-- back an /equivalent/ type formed of toplevel `:<|>`-separated chains of `:>`s,
|
||||||
|
-- i.e with all `:>`s distributed inside the `:<|>`s.
|
||||||
|
--
|
||||||
|
-- It basically turns:
|
||||||
|
--
|
||||||
|
-- > "hello" :> (Get Hello :<|> ReqBody Hello :> Put Hello)
|
||||||
|
--
|
||||||
|
-- into
|
||||||
|
--
|
||||||
|
-- > ("hello" :> Get Hello) :<|> ("hello" :> ReqBody Hello :> Put Hello)
|
||||||
|
--
|
||||||
|
-- i.e distributing all ':>'-separated bits into the subsequent ':<|>'s.
|
||||||
|
type family Canonicalize api :: * where
|
||||||
|
-- requires UndecidableInstances
|
||||||
|
Canonicalize (a :> (b :<|> c)) = a :> Canonicalize b :<|> a :> Canonicalize c
|
||||||
|
Canonicalize ((a :<|> b) :> c) = a :> Canonicalize c :<|> b :> Canonicalize c
|
||||||
|
Canonicalize (a :> b) = Redex b (Canonicalize b) a
|
||||||
|
Canonicalize (a :<|> b) = Canonicalize a :<|> Canonicalize b
|
||||||
|
Canonicalize a = a
|
||||||
|
|
||||||
|
type family Redex a b c :: * where
|
||||||
|
Redex a a first = Canonicalize first :> a
|
||||||
|
Redex a b first = Canonicalize (first :> b)
|
||||||
|
|
||||||
|
canonicalize :: Proxy layout -> Proxy (Canonicalize layout)
|
||||||
|
canonicalize Proxy = Proxy
|
||||||
|
|
|
@ -55,6 +55,8 @@ module Servant.API.ContentTypes
|
||||||
, AcceptHeader(..)
|
, AcceptHeader(..)
|
||||||
, AllCTRender(..)
|
, AllCTRender(..)
|
||||||
, AllCTUnrender(..)
|
, AllCTUnrender(..)
|
||||||
|
, AllMimeRender(..)
|
||||||
|
, AllMimeUnrender(..)
|
||||||
, FromFormUrlEncoded(..)
|
, FromFormUrlEncoded(..)
|
||||||
, ToFormUrlEncoded(..)
|
, ToFormUrlEncoded(..)
|
||||||
, IsNonEmpty
|
, IsNonEmpty
|
||||||
|
|
Loading…
Reference in a new issue