{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} -- | Defines types and kinds for working with type and value level HTTP -- verbs. module Network.HTTP.Kinder.Verb ( -- * Functions and types for working with 'HeaderName' 'Sing's verbName , parseVerb -- * The 'Verb' type/kind , Verb (..) , Sing ( SDELETE, SGET, SHEAD, SOPTIONS, SPATCH, SPOST, SPUT ) -- * Type synonyms for more convenient use of 'HeaderName's , DELETE , GET , HEAD , OPTIONS , PATCH , POST , PUT ) where import qualified Data.ByteString as S import qualified Data.CaseInsensitive as CI import Data.Singletons.Prelude import Data.String -- | A data type representing HTTP verbs. Much more importantly, with -- @DataKinds@ enabled this becomes a kind describing types, one for each -- such verb. -- -- Use 'Verb' at both the kind and type levels---it works equally well at -- both unlike, e.g., 'HeaderName'. Use methods of 'SingKind' to convert -- between 'Verb' values and 'Verb' 'Sing's -- -- Note: TRACE is intentionally omitted because (a) it's very low value and -- (b) it opens a potential security hole via Cross-Site-Tracing. data Verb = DELETE | GET | HEAD | OPTIONS | PATCH | POST | PUT deriving ( Eq, Ord, Show, Read ) type DELETE = 'DELETE type GET = 'GET type HEAD = 'HEAD type OPTIONS = 'OPTIONS type PATCH = 'PATCH type POST = 'POST type PUT = 'PUT data instance Sing (v :: Verb) = v ~ DELETE => SDELETE | v ~ GET => SGET | v ~ HEAD => SHEAD | v ~ OPTIONS => SOPTIONS | v ~ PATCH => SPATCH | v ~ POST => SPOST | v ~ PUT => SPUT instance SingI 'DELETE where sing = SDELETE instance SingI 'GET where sing = SGET instance SingI 'HEAD where sing = SHEAD instance SingI 'OPTIONS where sing = SOPTIONS instance SingI 'PATCH where sing = SPATCH instance SingI 'POST where sing = SPOST instance SingI 'PUT where sing = SPUT instance SingKind ('KProxy :: KProxy Verb) where type DemoteRep ('KProxy :: KProxy Verb) = Verb fromSing s = case s of SDELETE -> DELETE SGET -> GET SHEAD -> HEAD SOPTIONS -> OPTIONS SPATCH -> PATCH SPOST -> POST SPUT -> PUT toSing v = case v of DELETE -> SomeSing SDELETE GET -> SomeSing SGET HEAD -> SomeSing SHEAD OPTIONS -> SomeSing SOPTIONS PATCH -> SomeSing SPATCH POST -> SomeSing SPOST PUT -> SomeSing SPUT -- | Convert a 'Verb' to its string-like representation verbName :: IsString t => Verb -> t verbName v = case v of GET -> "GET" HEAD -> "HEAD" POST -> "POST" PUT -> "PUT" PATCH -> "PATCH" DELETE -> "DELETE" OPTIONS -> "OPTIONS" -- | Attempt to parse a string-like representation of a 'Verb'. parseVerb :: S.ByteString -> Maybe Verb parseVerb s = case CI.mk s of "GET" -> Just GET "HEAD" -> Just HEAD "POST" -> Just POST "PUT" -> Just PUT "PATCH" -> Just PATCH "DELETE" -> Just DELETE "OPTIONS" -> Just OPTIONS _ -> Nothing