module Servant.API.Extended where
import Data.ByteString
import Data.ByteString.Lazy qualified as BL
import Data.EitherR (fmapL)
import Data.Kind
import Data.Metrics.Servant
import Data.Typeable
import GHC.TypeLits
import Imports
import Network.HTTP.Types hiding (Header, ResponseHeaders)
import Network.Wai
import Servant.API
import Servant.API.ContentTypes
import Servant.API.Modifiers
import Servant.OpenApi
import Servant.Server.Internal
import Prelude ()
data ReqBodyCustomError' (mods :: [Type]) (list :: [ct]) (tag :: Symbol) (a :: Type)
type ReqBodyCustomError = ReqBodyCustomError' '[Required, Strict]
class MakeCustomError (tag :: Symbol) (a :: Type) where
makeCustomError :: String -> ServerError
instance
( MakeCustomError tag a,
AllCTUnrender list a,
HasServer api context,
SBoolI (FoldLenient mods)
) =>
HasServer (ReqBodyCustomError' mods list tag a :> api) context
where
type
ServerT (ReqBodyCustomError' mods list tag a :> api) m =
If (FoldLenient mods) (Either ServerError a) a -> ServerT api m
hoistServerWithContext :: forall (m :: * -> *) (n :: * -> *).
Proxy (ReqBodyCustomError' mods list tag a :> api)
-> Proxy context
-> (forall x. m x -> n x)
-> ServerT (ReqBodyCustomError' mods list tag a :> api) m
-> ServerT (ReqBodyCustomError' mods list tag a :> api) n
hoistServerWithContext Proxy (ReqBodyCustomError' mods list tag a :> api)
_ Proxy context
pc forall x. m x -> n x
nt ServerT (ReqBodyCustomError' mods list tag a :> api) m
s = Proxy api
-> Proxy context
-> (forall x. m x -> n x)
-> ServerT api m
-> ServerT api n
forall {k} (api :: k) (context :: [*]) (m :: * -> *) (n :: * -> *).
HasServer api context =>
Proxy api
-> Proxy context
-> (forall x. m x -> n x)
-> ServerT api m
-> ServerT api n
forall (m :: * -> *) (n :: * -> *).
Proxy api
-> Proxy context
-> (forall x. m x -> n x)
-> ServerT api m
-> ServerT api n
hoistServerWithContext (Proxy api
forall {k} (t :: k). Proxy t
Proxy :: Proxy api) Proxy context
pc m x -> n x
forall x. m x -> n x
nt (ServerT api m -> ServerT api n)
-> (If (FoldLenient mods) (Either ServerError a) a
-> ServerT api m)
-> If (FoldLenient mods) (Either ServerError a) a
-> ServerT api n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ServerT (ReqBodyCustomError' mods list tag a :> api) m
If (FoldLenient mods) (Either ServerError a) a -> ServerT api m
s
route :: forall env.
Proxy (ReqBodyCustomError' mods list tag a :> api)
-> Context context
-> Delayed
env (Server (ReqBodyCustomError' mods list tag a :> api))
-> Router env
route Proxy (ReqBodyCustomError' mods list tag a :> api)
Proxy Context context
context Delayed env (Server (ReqBodyCustomError' mods list tag a :> api))
subserver =
Proxy api
-> Context context -> Delayed env (Server api) -> Router env
forall env.
Proxy api
-> Context context -> Delayed env (Server api) -> Router env
forall {k} (api :: k) (context :: [*]) env.
HasServer api context =>
Proxy api
-> Context context -> Delayed env (Server api) -> Router env
route (Proxy api
forall {k} (t :: k). Proxy t
Proxy :: Proxy api) Context context
context (Delayed env (Server api) -> Router env)
-> Delayed env (Server api) -> Router env
forall a b. (a -> b) -> a -> b
$
Delayed
env (If (FoldLenient mods) (Either ServerError a) a -> Server api)
-> DelayedIO (ByteString -> Either String a)
-> ((ByteString -> Either String a)
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a))
-> Delayed env (Server api)
forall env a b c.
Delayed env (a -> b)
-> DelayedIO c -> (c -> DelayedIO a) -> Delayed env b
addBodyCheck Delayed env (Server (ReqBodyCustomError' mods list tag a :> api))
Delayed
env (If (FoldLenient mods) (Either ServerError a) a -> Server api)
subserver DelayedIO (ByteString -> Either String a)
ctCheck (ByteString -> Either String a)
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
bodyCheck
where
ctCheck :: DelayedIO (ByteString -> Either String a)
ctCheck = (Request -> DelayedIO (ByteString -> Either String a))
-> DelayedIO (ByteString -> Either String a)
forall a. (Request -> DelayedIO a) -> DelayedIO a
withRequest ((Request -> DelayedIO (ByteString -> Either String a))
-> DelayedIO (ByteString -> Either String a))
-> (Request -> DelayedIO (ByteString -> Either String a))
-> DelayedIO (ByteString -> Either String a)
forall a b. (a -> b) -> a -> b
$ \Request
request -> do
let contentTypeH :: ByteString
contentTypeH =
ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ByteString
"application/octet-stream" (Maybe ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$
HeaderName -> [(HeaderName, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
hContentType ([(HeaderName, ByteString)] -> Maybe ByteString)
-> [(HeaderName, ByteString)] -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$
Request -> [(HeaderName, ByteString)]
requestHeaders Request
request
case Proxy list -> ByteString -> Maybe (ByteString -> Either String a)
forall (list :: [*]) a.
AllCTUnrender list a =>
Proxy list -> ByteString -> Maybe (ByteString -> Either String a)
canHandleCTypeH (Proxy list
forall {k} (t :: k). Proxy t
Proxy :: Proxy list) (ByteString -> ByteString
fromStrict ByteString
contentTypeH) :: Maybe (BL.ByteString -> Either String a) of
Maybe (ByteString -> Either String a)
Nothing -> ServerError -> DelayedIO (ByteString -> Either String a)
forall a. ServerError -> DelayedIO a
delayedFail ServerError
err415
Just ByteString -> Either String a
f -> (ByteString -> Either String a)
-> DelayedIO (ByteString -> Either String a)
forall a. a -> DelayedIO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString -> Either String a
f
bodyCheck ::
(BL.ByteString -> Either String a) ->
DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
bodyCheck :: (ByteString -> Either String a)
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
bodyCheck ByteString -> Either String a
f = (Request
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a))
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
forall a. (Request -> DelayedIO a) -> DelayedIO a
withRequest ((Request
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a))
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a))
-> (Request
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a))
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
forall a b. (a -> b) -> a -> b
$ \Request
request -> do
Either ServerError a
mrqbody <- (String -> ServerError) -> Either String a -> Either ServerError a
forall a b r. (a -> b) -> Either a r -> Either b r
fmapL (forall (tag :: Symbol) a.
MakeCustomError tag a =>
String -> ServerError
makeCustomError @tag @a) (Either String a -> Either ServerError a)
-> (ByteString -> Either String a)
-> ByteString
-> Either ServerError a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String a
f (ByteString -> Either ServerError a)
-> DelayedIO ByteString -> DelayedIO (Either ServerError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO ByteString -> DelayedIO ByteString
forall a. IO a -> DelayedIO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Request -> IO ByteString
lazyRequestBody Request
request)
case SBool (FoldLenient mods)
forall (b :: Bool). SBoolI b => SBool b
sbool :: SBool (FoldLenient mods) of
SBool (FoldLenient mods)
STrue -> If (FoldLenient mods) (Either ServerError a) a
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
forall a. a -> DelayedIO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Either ServerError a
If (FoldLenient mods) (Either ServerError a) a
mrqbody
SBool (FoldLenient mods)
SFalse -> case Either ServerError a
mrqbody of
Left ServerError
e -> ServerError
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
forall a. ServerError -> DelayedIO a
delayedFailFatal ServerError
e
Right a
v -> If (FoldLenient mods) (Either ServerError a) a
-> DelayedIO (If (FoldLenient mods) (Either ServerError a) a)
forall a. a -> DelayedIO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
If (FoldLenient mods) (Either ServerError a) a
v
instance
(HasOpenApi (ReqBody' '[Required, Strict] cts a :> api)) =>
HasOpenApi (ReqBodyCustomError cts tag a :> api)
where
toOpenApi :: Proxy (ReqBodyCustomError cts tag a :> api) -> OpenApi
toOpenApi Proxy (ReqBodyCustomError cts tag a :> api)
Proxy = Proxy (ReqBody' '[Required, Strict] cts a :> api) -> OpenApi
forall {k} (api :: k). HasOpenApi api => Proxy api -> OpenApi
toOpenApi (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(ReqBody' '[Required, Strict] cts a :> api))
instance (RoutesToPaths rest) => RoutesToPaths (ReqBodyCustomError' mods list tag a :> rest) where
getRoutes :: Forest PathSegment
getRoutes = forall routes. RoutesToPaths routes => Forest PathSegment
forall {k} (routes :: k).
RoutesToPaths routes =>
Forest PathSegment
getRoutes @rest