packages feed

webgear-server-0.1.0: src/WebGear/Trait/Method.hs

-- |
-- Copyright        : (c) Raghu Kaippully, 2020
-- License          : MPL-2.0
-- Maintainer       : rkaippully@gmail.com
--
-- Trait capturing the HTTP method in a request.
module WebGear.Trait.Method
  ( Method
  , IsStdMethod (..)
  , MethodMismatch (..)
  ) where

import Data.Proxy (Proxy (..))

import WebGear.Trait (CheckResult (..), Trait (..))
import WebGear.Types (Request, requestMethod)

import qualified Network.HTTP.Types as HTTP


-- | A 'Trait' for capturing the HTTP method of a request
data Method (t :: HTTP.StdMethod)

-- | Failure to match method against an expected value
data MethodMismatch = MethodMismatch
  { expectedMethod :: HTTP.Method
  , actualMethod   :: HTTP.Method
  }

instance (Monad m, IsStdMethod t) => Trait (Method t) Request m where
  type Val (Method t) Request = HTTP.Method
  type Fail (Method t) Request = MethodMismatch

  check :: Request -> m (CheckResult (Method t) Request)
  check r =
    let
      expected = HTTP.renderStdMethod $ toStdMethod $ Proxy @t
      actual = requestMethod r
    in
      pure $ if expected == actual
             then CheckSuccess r actual
             else CheckFail $ MethodMismatch expected actual


-- | A typeclass implemented by all 'HTTP.StdMethod's to convert them
-- from type level to term level.
class IsStdMethod t where
  -- | Convert @t@ to term level.
  toStdMethod :: Proxy t -> HTTP.StdMethod

instance IsStdMethod HTTP.GET where
  toStdMethod = const HTTP.GET
instance IsStdMethod HTTP.POST where
  toStdMethod = const HTTP.POST
instance IsStdMethod HTTP.HEAD where
  toStdMethod = const HTTP.HEAD
instance IsStdMethod HTTP.PUT where
  toStdMethod = const HTTP.PUT
instance IsStdMethod HTTP.DELETE where
  toStdMethod = const HTTP.DELETE
instance IsStdMethod HTTP.TRACE where
  toStdMethod = const HTTP.TRACE
instance IsStdMethod HTTP.CONNECT where
  toStdMethod = const HTTP.CONNECT
instance IsStdMethod HTTP.OPTIONS where
  toStdMethod = const HTTP.OPTIONS
instance IsStdMethod HTTP.PATCH where
  toStdMethod = const HTTP.PATCH