packages feed

eved-0.0.1.0: src/Web/Eved/Options.hs

{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}

module Web.Eved.Options
    where

import qualified Data.ByteString    as B
import           Data.Coerce        (coerce)
import           Data.Text          (Text)
import           Network.HTTP.Types
import           Network.Wai
import           Web.Eved.Internal

provideOptions :: EvedOptions m a -> Middleware
provideOptions api app req respond
  | requestMethod req == "OPTIONS" = respond (getOptionsResponse api req)
  | otherwise = app req respond

getOptionsResponse :: EvedOptions m a -> Request -> Response
getOptionsResponse api req =
    let methods = fmap renderStdMethod $ getAvailableMethods api (pathInfo req)
        headers = [ ("Allow", B.intercalate ", " $ "OPTIONS":methods) ]
    in responseBuilder status200 headers mempty

newtype EvedOptions (m :: * -> *) a = EvedOptions
    { getAvailableMethods :: [Text] -> [StdMethod]
    }

passthrough :: EvedOptions m a -> EvedOptions m b
passthrough = coerce

instance Eved (EvedOptions m) m where
    left .<|> right = EvedOptions $ \path ->
        getAvailableMethods left path <> getAvailableMethods right path

    lit t next = EvedOptions $ \path ->
        case path of
          p:rest | p == t -> getAvailableMethods next rest
          _               -> mempty

    capture _ _ next = EvedOptions $ \path ->
        case path of
          _:rest -> getAvailableMethods next rest
          _      -> mempty

    reqBody _ = passthrough
    queryParam _ _ = passthrough
    verb method _ _ = EvedOptions $ \path ->
        case path of
          [] -> [method]
          _  -> mempty