packages feed

mig-extra-0.1.1.0: src/Mig/Extra/Server/Json.hs

{-# LANGUAGE UndecidableInstances #-}

-- | Json servers
module Mig.Extra.Server.Json (
  -- * Http verbs
  Get,
  Post,
  Put,
  Delete,
  Patch,
  Options,
  Head,
  Trace,

  -- * Json request body
  Body (..),

  -- * Json response
  Resp,
  RespOr,

  -- * re-exports
  module X,
)
where

import Mig.Client (FromClient (..), ToClient (..))
import Mig.Core (
  Delete,
  Get,
  Head,
  Options,
  Patch,
  Post,
  Put,
  Trace,
 )
import Mig.Core qualified as Core
import Mig.Extra.Server.Common as X

-- response

newtype Resp a = Resp (Core.Resp Json a)
  deriving newtype (IsResp, Eq, Show, Functor)

newtype RespOr err a = RespOr (Core.RespOr Json err a)
  deriving newtype (IsResp, Eq, Show, Functor)

-- request

-- | Special case for request Body with JSON.
newtype Body a = Body a

instance (ToSchema a, FromJSON a, ToRoute b) => ToRoute (Body a -> b) where
  toRouteInfo = toRouteInfo @(Core.Body Json a -> b)

  toRouteFun f =
    (toRouteFun :: ((Core.Body Json a -> b) -> ServerFun (Core.MonadOf b)))
      (\(Core.Body a) -> f (Body a))

instance (FromJSON a, ToSchema a, ToPlugin b) => ToPlugin (Body a -> b) where
  toPluginInfo = toPluginInfo @(Core.Body Json a -> b)

  toPluginFun f =
    (toPluginFun :: ((Core.Body Json a -> b) -> PluginFun (Core.MonadOf b)))
      (\(Core.Body a) -> f (Body a))

-- client instances

instance (ToJSON a, ToClient b) => ToClient (Body a -> b) where
  toClient api = (\f -> \(Body b) -> f (Core.Body b)) $ toClient @(Core.Body Json a -> b) api
  clientArity = clientArity @(Core.Body Json a -> b)

instance (FromClient b) => FromClient (Body a -> b) where
  type ClientResult (Body a -> b) = ClientResult (Core.Body Json a -> b)
  fromClient f arg = fromClient @(Core.Body Json a -> b) (f . Body . fromBody) arg
    where
      fromBody (Core.Body a) = a