content: -- | Specification for an API endpoint as a composition of Request and Response components
  -- at the Type level.
  module Hreq.Core.API.Internal where
  
  import Data.Kind (Type)
  import Data.Singletons
  import GHC.TypeLits
  
  import Hreq.Core.API.Request
  import Hreq.Core.API.Response
  
  -- * API type
  data Api a =
      Req [ ReqContent a]
    | Res [ ResContent a ]
  
  -- * API GADT as a singleton.
  data SApi (a :: Api Type)
    = forall b . a ~ 'Req b => SReq (Sing b)
    | forall b . a ~ 'Res b => SRes (Sing b)
  type instance Sing = SApi
  
  -- * SingI instance for API types
  instance (SingI content) => SingI ('Res content :: Api Type) where
    sing = SRes sing
  
  instance (SingI content) => SingI ('Req content :: Api Type) where
    sing = SReq sing
  
  -- * API Type combinators
  -- Used in concatenation of API types.
  --
  -- Examples
  --
  -- >>> PathQueryWithEmptyResponse = "hello" :> QueryFlag "young" :> Get '[]
  -- >>> PathQueryWithResponse = "hello" :> QueryFlag "young" :> Get '[ ResBody JSON String, ResHeader [ "headerName" := String ]]
  -- >>> JsonBodyAndResponse = "hello" :> JsonBody User :> GetJson User
  
  infixr 7 :>
  
  data (a :: k1) :> (b :: k2)
  
  -- | For representing type level tuples where first value is a Symbol
  infixr 1 :=
  
  type (a :: Symbol) := (b :: k2) = '( a, b)
  
  -- $setup
  -- >>> import Hreq.Core.API
  -- >>> import GHC.Generics
  -- >>> import Data.Aeson
  -- >>> data User = User deriving (Show)
  -- >>> instance ToJSON User where toJSON = undefined
  -- >>> instance FromJSON User where parseJSON = undefined
  