packages feed

grpc-spec-1.0.0: src/Network/GRPC/Spec/Serialization/Headers/PseudoHeaders.hs

{-# LANGUAGE OverloadedStrings #-}

module Network.GRPC.Spec.Serialization.Headers.PseudoHeaders (
    RawResourceHeaders(..)
  , InvalidResourceHeaders(..)
  , buildResourceHeaders
  , parseResourceHeaders
  ) where

import Control.Monad.Except
import Data.ByteString qualified as BS.Strict
import Data.ByteString qualified as Strict (ByteString)

import Network.GRPC.Spec
import Network.GRPC.Spec.Util.ByteString

{-------------------------------------------------------------------------------
  Serialization
-------------------------------------------------------------------------------}

-- | Raw (serialized) form of t'ResourceHeaders'
data RawResourceHeaders = RawResourceHeaders {
      rawPath   :: Strict.ByteString  -- ^ Serialized 'resourcePath'
    , rawMethod :: Strict.ByteString  -- ^ Serialized 'resourceMethod'
    }
  deriving (Show)

-- | Invalid resource headers
--
-- See 'parseResourceHeaders'
data InvalidResourceHeaders =
    InvalidMethod Strict.ByteString
  | InvalidPath Strict.ByteString
  deriving stock (Show)

-- | Serialize t'ResourceHeaders' (pseudo headers)
buildResourceHeaders :: ResourceHeaders -> RawResourceHeaders
buildResourceHeaders ResourceHeaders{resourcePath, resourceMethod} =
    RawResourceHeaders {
        rawMethod = case resourceMethod of Post -> "POST"
      , rawPath   = mconcat [
                        "/"
                      , pathService resourcePath
                      , "/"
                      , pathMethod resourcePath
                      ]
      }

-- | Parse t'ResourceHeaders' (pseudo headers)
parseResourceHeaders ::
     RawResourceHeaders
  -> Either InvalidResourceHeaders ResourceHeaders
parseResourceHeaders RawResourceHeaders{rawMethod, rawPath} = do
    resourceMethod <-
      case rawMethod of
        "POST"     -> return Post
        _otherwise -> throwError $ InvalidMethod rawMethod

    resourcePath <-
      case BS.Strict.split (ascii '/') rawPath of
        ["", service, method] ->
          return $ Path service method
        _otherwise ->
          throwError $ InvalidPath rawPath

    return ResourceHeaders{resourceMethod, resourcePath}