packages feed

mig 0.1.0.1 → 0.1.0.2

raw patch · 9 files changed

+94/−143 lines, 9 filesdep +case-insensitivedep +http-api-datadep −randomdep −wai-extraPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: case-insensitive, http-api-data

Dependencies removed: random, wai-extra

API changes (from Hackage documentation)

- Mig: FormJson :: a -> FormJson a
- Mig: RawFormData :: FormBody -> RawFormData
- Mig: [$sel:files:FormBody] :: FormBody -> [(ByteString, FileInfo ByteString)]
- Mig: [$sel:params:FormBody] :: FormBody -> [(ByteString, ByteString)]
- Mig: data FormBody
- Mig: instance (Mig.FromText a, Mig.ToServer b) => Mig.ToServer (Mig.Capture a -> b)
- Mig: instance (Mig.FromText a, Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Optional sym a -> b)
- Mig: instance (Mig.FromText a, Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Query sym a -> b)
- Mig: instance (Mig.ToServer b, Control.Monad.IO.Class.MonadIO (Mig.ServerMonad b)) => Mig.ToServer (Mig.RawFormData -> b)
- Mig: instance (Mig.ToServer b, Control.Monad.IO.Class.MonadIO (Mig.ServerMonad b), Data.Aeson.Types.FromJSON.FromJSON a) => Mig.ToServer (Mig.FormJson a -> b)
- Mig: instance (Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Header sym -> b)
- Mig: newtype FormJson a
- Mig: newtype RawFormData
- Mig.Common: FormJson :: a -> FormJson a
- Mig.Common: RawFormData :: FormBody -> RawFormData
- Mig.Common: [$sel:files:FormBody] :: FormBody -> [(ByteString, FileInfo ByteString)]
- Mig.Common: [$sel:params:FormBody] :: FormBody -> [(ByteString, ByteString)]
- Mig.Common: data FormBody
- Mig.Common: newtype FormJson a
- Mig.Common: newtype RawFormData
- Mig.Internal.Types: FormBody :: [(ByteString, ByteString)] -> [(ByteString, FileInfo ByteString)] -> FormBody
- Mig.Internal.Types: [$sel:files:FormBody] :: FormBody -> [(ByteString, FileInfo ByteString)]
- Mig.Internal.Types: [$sel:params:FormBody] :: FormBody -> [(ByteString, ByteString)]
- Mig.Internal.Types: [$sel:readFormBody:Req] :: Req -> IO (Either (Error Text) FormBody)
- Mig.Internal.Types: data FormBody
+ Mig: instance (Mig.ToServer b, Control.Monad.IO.Class.MonadIO (Mig.ServerMonad b), Web.Internal.FormUrlEncoded.FromForm a) => Mig.ToServer (Mig.FormBody a -> b)
+ Mig: instance (Web.Internal.HttpApiData.FromHttpApiData a, Mig.ToServer b) => Mig.ToServer (Mig.Capture a -> b)
+ Mig: instance (Web.Internal.HttpApiData.FromHttpApiData a, Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Header sym a -> b)
+ Mig: instance (Web.Internal.HttpApiData.FromHttpApiData a, Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Optional sym a -> b)
+ Mig: instance (Web.Internal.HttpApiData.FromHttpApiData a, Mig.ToServer b, GHC.TypeLits.KnownSymbol sym) => Mig.ToServer (Mig.Query sym a -> b)
+ Mig: newtype FormBody a
+ Mig.Common: newtype FormBody a
- Mig: FormBody :: [(ByteString, ByteString)] -> [(ByteString, FileInfo ByteString)] -> FormBody
+ Mig: FormBody :: a -> FormBody a
- Mig: Header :: Maybe ByteString -> Header (sym :: Symbol)
+ Mig: Header :: Maybe a -> Header (sym :: Symbol) a
- Mig: newtype Header (sym :: Symbol)
+ Mig: newtype Header (sym :: Symbol) a
- Mig.Common: FormBody :: [(ByteString, ByteString)] -> [(ByteString, FileInfo ByteString)] -> FormBody
+ Mig.Common: FormBody :: a -> FormBody a
- Mig.Common: Header :: Maybe ByteString -> Header (sym :: Symbol)
+ Mig.Common: Header :: Maybe a -> Header (sym :: Symbol) a
- Mig.Common: newtype Header (sym :: Symbol)
+ Mig.Common: newtype Header (sym :: Symbol) a
- Mig.Internal.Types: Req :: [Text] -> QueryMap -> RequestHeaders -> Method -> IO (Either (Error Text) ByteString) -> IO (Either (Error Text) FormBody) -> Req
+ Mig.Internal.Types: Req :: [Text] -> QueryMap -> RequestHeaders -> Method -> IO (Either (Error Text) ByteString) -> Req
- Mig.Internal.Types: toWithFormData :: MonadIO m => (FormBody -> Server m) -> Server m
+ Mig.Internal.Types: toWithFormData :: (FromForm a, MonadIO m) => (a -> Server m) -> Server m
- Mig.Internal.Types: toWithHeader :: HeaderName -> (Maybe ByteString -> Server m) -> Server m
+ Mig.Internal.Types: toWithHeader :: (Monad m, FromHttpApiData a) => HeaderName -> (Maybe a -> Server m) -> Server m

Files

README.md view
@@ -164,16 +164,17 @@  We have newtypes for: -* `Query "name" type` - required query parameter-* `Optional "name" type` - optional query parameter-* `Capture type` - capture part of the URI between slashes `/`.-* `Body type` - input JSON body-* `RawBody` - input body as raw lazy bytestring-* `RawFormData` - input of the html-form-* `FormJson` - input f html-form as Json (see examples/Html.hs)-* `Header "name"` - access header by name-* `PathInfo` - access path info relative to the server+* `Query "name" type` - required query parameter (`FromHttpApiData`)+* `Optional "name" type` - optional query parameter (`FromHttpApiData`)+* `Capture type` - capture part of the URI between slashes `/`. (`FromHttpApiData`)+* `Body type` - input JSON body (`FromJSON`)+* `RawBody` - input body as raw lazy bytestring (is `ByteString`)+* `FormBody` - input URL-encoded form (it often comes from HTML-forms) (`FromForm`)+* `Header "name" ty` - access header by name (`FromHttpApiData`)+* `PathInfo` - access path info relative to the server (is `[Text]`) +Class at in the parens is which class is used for convertion.+Often we can derive the instance of that class with newtype-deriving or with Generic-deriving. We can change the number of arguments because the function `(/.)` is overloaded by second argument and it can accept anything convertible to `Server` or an instance of the class `ToServer`.
mig.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           mig-version:        0.1.0.1+version:        0.1.0.2 synopsis:       Build lightweight and composable servers description:    With library mig we can build lightweight and composable servers.                 There are only couple of combinators to assemble servers from parts.@@ -105,13 +105,13 @@     , blaze-html     , blaze-markup     , bytestring+    , case-insensitive     , containers     , exceptions+    , http-api-data     , http-types     , mtl-    , random     , text     , wai-    , wai-extra     , warp   default-language: GHC2021
src/Mig.hs view
@@ -41,9 +41,7 @@   , Body (..)   , RawBody (..)   , Header (..)-  , RawFormData (..)   , FormBody (..)-  , FormJson (..)   , PathInfo (..)    -- ** response@@ -87,7 +85,8 @@ import Mig.Internal.Types import Mig.Internal.Types qualified as Resp (Resp (..)) -+import Web.HttpApiData as X+import Web.FormUrlEncoded as X import Data.Bifunctor import Data.Kind import Data.String@@ -113,7 +112,6 @@ import Network.Wai.Handler.Warp qualified as Warp import Control.Exception (throw) import Data.Typeable-import Data.Aeson.Key qualified as Json  -- | Path constructor (right associative). Example: --@@ -172,19 +170,19 @@ toWithQuery name act = Server $ \req ->   unServer (act (Map.lookup name req.query)) req -withQuery' :: FromText a => QueryName a -> (Maybe a -> Server m) -> Server m+withQuery' :: FromHttpApiData a => QueryName a -> (Maybe a -> Server m) -> Server m withQuery' (QueryName name) act = toWithQuery (Text.encodeUtf8 name) $ \mVal ->   let     -- TODO: do not ignore parse failure-    mArg = fromText =<< either (const Nothing) Just . Text.decodeUtf8' =<< mVal+    mArg = either (const Nothing) Just . (parseQueryParam <=< first (Text.pack . show) . Text.decodeUtf8') =<< mVal   in     act mArg -withQuery :: (Applicative m, FromText a) => QueryName a -> (a -> Server m) -> Server m+withQuery :: (Applicative m, FromHttpApiData a) => QueryName a -> (a -> Server m) -> Server m withQuery (QueryName name) act = toWithQuery (Text.encodeUtf8 name) $ \mVal ->   let     -- TODO: do not ignore parse failure-    mArg = fromText =<< either (const Nothing) Just . Text.decodeUtf8' =<< mVal+    mArg = either (const Nothing) Just . (parseQueryParam <=< first (Text.pack . show) . Text.decodeUtf8') =<< mVal   in     case mArg of       Just arg -> act arg@@ -507,7 +505,7 @@ -- > handleFoo (Query arg) = ... newtype Query (sym :: Symbol) a = Query a -instance (FromText a, ToServer b, KnownSymbol sym) => ToServer (Query sym a -> b) where+instance (FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Query sym a -> b) where   type ServerMonad (Query sym a -> b) = ServerMonad b   toServer act = withQuery (QueryName (Text.pack $ symbolVal (Proxy @sym))) (toServer . act . Query) @@ -521,11 +519,11 @@ -- > handleFoo (Optional maybeArg) = ... newtype Optional (sym :: Symbol) a = Optional (Maybe a) -instance (FromText a, ToServer b, KnownSymbol sym) => ToServer (Optional sym a -> b) where+instance (FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Optional sym a -> b) where   type ServerMonad (Optional sym a -> b) = ServerMonad b   toServer act = withQuery' (QueryName (fromString $ symbolVal (Proxy @sym))) (toServer . act . Optional) --- Capture+-- | Capture  -- Captures part of the path. Example --@@ -534,12 +532,12 @@ -- It will parse the paths: "api/foo/358" and pass 358 to @handleFoo@. newtype Capture a = Capture a -instance (FromText a, ToServer b) => ToServer (Capture a -> b) where+instance (FromHttpApiData a, ToServer b) => ToServer (Capture a -> b) where   type ServerMonad (Capture a -> b) = ServerMonad b   toServer act = toWithCapture $ \txt ->-    case fromText txt of-      Just val -> toServer $ act $ Capture val-      Nothing -> toConst $ pure $ badRequest "Failed to parse capture"+    case parseUrlPiece txt of+      Right val -> toServer $ act $ Capture val+      Left err -> toConst $ pure $ badRequest ("Failed to parse capture: " <> err)  -- Read Body input @@ -564,49 +562,12 @@   type ServerMonad (RawBody -> b) = ServerMonad b   toServer act = toWithBody $ toServer . act . RawBody --- | Parse raw form body. It includes named form arguments and file info.--- Note that we can not use FormBody and JSON-body at the same time.--- They occupy the same field in the HTTP-request.-newtype RawFormData = RawFormData FormBody--instance (ToServer b, MonadIO (ServerMonad b)) => ToServer (RawFormData -> b) where-  type ServerMonad (RawFormData -> b) = ServerMonad b-  toServer act = toWithFormData $ toServer . act . RawFormData---- | It reads form as plain JSON-object where name of the form's field becomes--- a field of JSON-object and every value is Text.------ For example if submit a form with fields: name, password, date.--- We can read it in the data type:------ > data User = User--- >  { name :: Text--- >  , passord :: Text--- >  , date :: Text--- >  }------ Note that we can not use FormBody and JSON-body at the same time.--- They occupy the same field in the HTTP-request.-newtype FormJson a = FormJson a--instance (ToServer b, MonadIO (ServerMonad b), FromJSON a) => ToServer (FormJson a -> b) where-  type ServerMonad (FormJson a -> b) = ServerMonad b-  toServer act = toWithFormData $ \formBody -> do-    case formDataToJson formBody.params of-      Right v -> toServer $ act $ FormJson v-      Left err -> toConst $-        pure $ badRequest $ "Failed to parse form data as JSON body: " <> err+-- | Reads the URL encoded Form input+newtype FormBody a = FormBody a -formDataToJson :: FromJSON a => [(ByteString, ByteString)] -> Either Text a-formDataToJson rawPairs = do-  jsonVal <- Json.object <$> mapM toPair rawPairs-  case Json.fromJSON jsonVal of-    Json.Success result -> Right result-    Json.Error err -> Left (Text.pack $ show err)-  where-    toPair (key, val) =-      first (Text.pack . show) $-        (\k v -> (Json.fromText k, Json.String v)) <$> Text.decodeUtf8' key <*> Text.decodeUtf8' val+instance (ToServer b, MonadIO (ServerMonad b), FromForm a) => ToServer (FormBody a -> b) where+  type ServerMonad (FormBody a -> b) = ServerMonad b+  toServer act = toWithFormData (toServer . act . FormBody)  -- Request Headers @@ -615,10 +576,10 @@ -- > "api" /. (\(Header @"Trace-Id" traceId) -> Post @Json (handleFoo traceId)) -- > -- > handleFoo :: Maybe ByteString -> IO FooResponse-newtype Header (sym :: Symbol) = Header (Maybe ByteString)+newtype Header (sym :: Symbol) a = Header (Maybe a) -instance (ToServer b, KnownSymbol sym) => ToServer (Header sym -> b) where-  type ServerMonad (Header sym -> b) = ServerMonad b+instance (FromHttpApiData a, ToServer b, KnownSymbol sym) => ToServer (Header sym a -> b) where+  type ServerMonad (Header sym a -> b) = ServerMonad b   toServer act = toWithHeader (fromString $ symbolVal (Proxy @sym)) (toServer . act . Header)  -- | Reads current path info
src/Mig/Common.hs view
@@ -16,9 +16,7 @@   , Body (..)   , RawBody (..)   , Header (..)-  , RawFormData (..)   , FormBody (..)-  , FormJson (..)   , PathInfo (..)    -- * response@@ -46,7 +44,9 @@  import Mig   ( Server (..), ToServer (..), ToText (..), ToHtmlResp (..), FromText (..), handleError, PathInfo (..)-  , (/.), Capture (..), Query (..), Optional (..), Body (..), RawBody (..), Header (..), RawFormData (..), FormBody (..), FormJson (..), AddHeaders (..), SetStatus (..)+  , (/.), Capture (..), Query (..), Optional (..), Body (..), RawBody (..), Header (..), FormBody (..), AddHeaders (..), SetStatus (..)   , setStatus, addHeaders, HasServer (..), fromReader, ServerConfig (..), toApplication, runServer, badRequest, Error (..), withServerAction)  import Network.HTTP.Types.Status as X+import Web.HttpApiData as X+import Web.FormUrlEncoded as X
src/Mig/Html.hs view
@@ -20,46 +20,43 @@  -- Get +-- | Get method. Note that we can not use body input with Get-method, use Post for that.+-- So with Get we can use only URI inputs (Query, Optional, Capture) newtype Get m a = Get (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Get m a) where   type ServerMonad (Get m a) = m   toServer (Get act) = toMethod methodGet (toHtmlResp <$> act) --- Post-+-- | Post method newtype Post m a = Post (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Post m a) where   type ServerMonad (Post m a) = m   toServer (Post act) = toMethod methodPost (toHtmlResp <$> act) --- Put-+-- | Put method newtype Put m a = Put (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Put m a) where   type ServerMonad (Put m a) = m   toServer (Put act) = toMethod methodPut (toHtmlResp <$> act) --- Delete-+-- | Delete method newtype Delete m a = Delete (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Delete m a) where   type ServerMonad (Delete m a) = m   toServer (Delete act) = toMethod methodDelete (toHtmlResp <$> act) --- Patch-+-- | Patch method newtype Patch m a = Patch (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Patch m a) where   type ServerMonad (Patch m a) = m   toServer (Patch act) = toMethod methodPatch (toHtmlResp <$> act) --- Options-+-- | Options method newtype Options m a = Options (m a)  instance (Monad m, ToHtmlResp a) => ToServer (Options m a) where
src/Mig/Html/IO.hs view
@@ -20,46 +20,43 @@  -- Get +-- | Get method. Note that we can not use body input with Get-method, use Post for that.+-- So with Get we can use only URI inputs (Query, Optional, Capture) newtype Get a = Get (IO a)  instance (ToHtmlResp a) => ToServer (Get a) where   type ServerMonad (Get a) = IO   toServer (Get act) = toMethod methodGet (toHtmlResp <$> act) --- Post-+-- | Post method newtype Post a = Post (IO a)  instance (ToHtmlResp a) => ToServer (Post a) where   type ServerMonad (Post a) = IO   toServer (Post act) = toMethod methodPost (toHtmlResp <$> act) --- Put-+-- | Put method newtype Put a = Put (IO a)  instance (ToHtmlResp a) => ToServer (Put a) where   type ServerMonad (Put a) = IO   toServer (Put act) = toMethod methodPut (toHtmlResp <$> act) --- Delete-+-- | Delete method newtype Delete a = Delete (IO a)  instance (ToHtmlResp a) => ToServer (Delete a) where   type ServerMonad (Delete a) = IO   toServer (Delete act) = toMethod methodDelete (toHtmlResp <$> act) --- Patch-+-- | Patch method newtype Patch a = Patch (IO a)  instance (ToHtmlResp a) => ToServer (Patch a) where   type ServerMonad (Patch a) = IO   toServer (Patch act) = toMethod methodPatch (toHtmlResp <$> act) --- Options-+-- | Options method newtype Options a = Options (IO a)  instance (ToHtmlResp a) => ToServer (Options a) where
src/Mig/Internal/Types.hs view
@@ -17,7 +17,6 @@   , toWithHeader   , toWithFormData   , toWithPathInfo-  , FormBody (..)   -- * responses   , text   , json@@ -67,7 +66,10 @@ import Control.Monad.IO.Class import Control.Monad.Catch import Data.Typeable-import Network.Wai.Parse qualified as Parse+import Web.FormUrlEncoded+import Web.HttpApiData+import Data.Either (fromRight)+import Data.CaseInsensitive qualified as CI  -- | Http response data Resp = Resp@@ -103,14 +105,8 @@     -- ^ request method   , readBody :: IO (Either (Error Text) BL.ByteString)     -- ^ lazy body reader. Error can happen if size is too big (configured on running the server)-  , readFormBody :: IO (Either (Error Text) FormBody)   } -data FormBody = FormBody-  { params :: [(ByteString, ByteString)]-  , files :: [(ByteString, Parse.FileInfo BL.ByteString)]-  }- -- Errors  -- | Errors@@ -181,9 +177,11 @@ -- * @Either (Error err)@ - to response with errors newtype Server m = Server { unServer :: Req -> m (Maybe Resp) } +-- | Replies to any http-method toConst :: Functor m => m Resp -> Server m toConst act = Server $ const $ Just <$> act +-- | Specify which method to reply toMethod :: Monad m => Method -> m Resp -> Server m toMethod method act = Server $ checkMethod method act @@ -192,6 +190,7 @@   | null req.path && req.method == method = Just <$> act   | otherwise = pure Nothing +-- | Reads full body as lazy bytestring toWithBody :: MonadIO m => (BL.ByteString -> Server m) -> Server m toWithBody act = Server $ \req -> do   eBody <- liftIO req.readBody@@ -199,14 +198,13 @@     Right body -> unServer (act body) req     Left err -> pure $ Just $ setRespStatus err.status (text err.body) --- TODO: make it size limited by HTTP-body size-toWithFormData :: MonadIO m => (FormBody -> Server m) -> Server m+-- | Reads URL-encoded form data+toWithFormData :: (FromForm a, MonadIO m) => (a -> Server m) -> Server m toWithFormData act = Server $ \req -> do-  eFormBody <- liftIO req.readFormBody-  case eFormBody of-    Right formBody -> unServer (act formBody) req-    Left err -> pure $ Just $ setRespStatus err.status (text err.body)-+  eBody <- first (\(Error _ details) -> details) <$> liftIO req.readBody+  case eBody >>= urlDecodeForm >>= fromForm of+    Right a -> unServer (act a) req+    Left err -> pure $ Just $ setRespStatus status413 $ badRequest err  -- | Size of the input body type Kilobytes = Int@@ -231,6 +229,7 @@       Just size -> \current -> current > size       Nothing -> const False +-- | Match path prefix toWithPath :: Monad m => Text -> Server m -> Server m toWithPath route act = Server $ \req ->   case hasPath route req.path of@@ -245,22 +244,34 @@   | otherwise = Nothing hasPath _ _ = Nothing +-- | Reads capture URL-piece element toWithCapture :: Monad m => (Text -> Server m) -> Server m toWithCapture act = Server $ \req ->   case pathHead req of     Just (arg, nextReq) -> unServer (act arg) nextReq     Nothing -> pure Nothing +-- | Match on path prefix pathHead :: Req -> Maybe (Text, Req) pathHead req =   case req.path of     hd : tl -> Just (hd, req { path = tl })     _ -> Nothing -toWithHeader :: HeaderName -> (Maybe ByteString -> Server m) -> Server m+-- | Read info from header+toWithHeader :: (Monad m, FromHttpApiData a) => HeaderName -> (Maybe a -> Server m) -> Server m toWithHeader name act = Server $ \req ->-  unServer (act (fmap snd $ List.find ((== name) . fst) req.headers)) req+  case fmap snd $ List.find ((== name) . fst) req.headers of+    Just bs ->+      case parseHeader bs of+        Right val -> unServer (act (Just val)) req+        Left err -> pure $ Just $ badRequest (errMessage err)+    Nothing -> unServer (act Nothing) req+  where+    errMessage :: Text -> Text+    errMessage err = "Failed to parse header " <> (fromRight "" $ Text.decodeUtf8' $ CI.original name) <> ": " <> err +-- | reads path info toWithPathInfo :: ([Text] -> Server m) -> Server m toWithPathInfo act = Server $ \req ->   unServer (act req.path) req@@ -298,6 +309,7 @@ setContent contentType =   [("Content-Type", contentType <>"; charset=utf-8")] +-- | Sets response status setRespStatus :: Status -> Resp -> Resp setRespStatus status (Resp _ headers body) = Resp status headers body @@ -368,16 +380,5 @@     , headers = requestHeaders req     , method = requestMethod req     , readBody = fmap (fmap BL.fromChunks) $ readRequestBody (getRequestBodyChunk req) maxSize-    , readFormBody = getReadFormBody req     }--getReadFormBody :: Request -> IO (Either (Error Text) FormBody)-getReadFormBody req = do-  case Parse.getRequestBodyType req of-    Nothing -> pure $ Right (FormBody [] [])-    Just reqBodyType -> do-      eResult <- try @IO @SomeException (Parse.sinkRequestBody Parse.lbsBackEnd reqBodyType (getRequestBodyChunk req))-      pure $ bimap (const toError) (uncurry FormBody) eResult-  where-    toError = Error status413 (Text.pack $ "Request is too big!") 
src/Mig/Json.hs view
@@ -21,46 +21,43 @@  -- Get +-- | Get method. Note that we can not use body input with Get-method, use Post for that.+-- So with Get we can use only URI inputs (Query, Optional, Capture) newtype Get m a = Get (m a)  instance (Monad m, ToJsonResp a) => ToServer (Get m a) where   type ServerMonad (Get m a) = m   toServer (Get act) = toMethod methodGet (toJsonResp <$> act) --- Post-+-- | Post method newtype Post m a = Post (m a)  instance (Monad m, ToJsonResp a) => ToServer (Post m a) where   type ServerMonad (Post m a) = m   toServer (Post act) = toMethod methodPost (toJsonResp <$> act) --- Put-+-- | Put method newtype Put m a = Put (m a)  instance (Monad m, ToJsonResp a) => ToServer (Put m a) where   type ServerMonad (Put m a) = m   toServer (Put act) = toMethod methodPut (toJsonResp <$> act) --- Delete-+-- | Delete method newtype Delete m a = Delete (m a)  instance (Monad m, ToJsonResp a) => ToServer (Delete m a) where   type ServerMonad (Delete m a) = m   toServer (Delete act) = toMethod methodDelete (toJsonResp <$> act) --- Patch-+-- | Patch method newtype Patch m a = Patch (m a)  instance (Monad m, ToJsonResp a) => ToServer (Patch m a) where   type ServerMonad (Patch m a) = m   toServer (Patch act) = toMethod methodPatch (toJsonResp <$> act) --- Options-+-- | Options method newtype Options m a = Options (m a)  instance (Monad m, ToJsonResp a) => ToServer (Options m a) where
src/Mig/Json/IO.hs view
@@ -21,46 +21,43 @@  -- Get +-- | Get method. Note that we can not use body input with Get-method, use Post for that.+-- So with Get we can use only URI inputs (Query, Optional, Capture) newtype Get a = Get (IO a)  instance (ToJsonResp a) => ToServer (Get a) where   type ServerMonad (Get a) = IO   toServer (Get act) = toMethod methodGet (toJsonResp <$> act) --- Post-+-- | Post method newtype Post a = Post (IO a)  instance (ToJsonResp a) => ToServer (Post a) where   type ServerMonad (Post a) = IO   toServer (Post act) = toMethod methodPost (toJsonResp <$> act) --- Put-+-- | Put method newtype Put a = Put (IO a)  instance (ToJsonResp a) => ToServer (Put a) where   type ServerMonad (Put a) = IO   toServer (Put act) = toMethod methodPut (toJsonResp <$> act) --- Delete-+-- | Delete method newtype Delete a = Delete (IO a)  instance (ToJsonResp a) => ToServer (Delete a) where   type ServerMonad (Delete a) = IO   toServer (Delete act) = toMethod methodDelete (toJsonResp <$> act) --- Patch-+-- | Patch method newtype Patch a = Patch (IO a)  instance (ToJsonResp a) => ToServer (Patch a) where   type ServerMonad (Patch a) = IO   toServer (Patch act) = toMethod methodPatch (toJsonResp <$> act) --- Options-+-- | Options method newtype Options a = Options (IO a)  instance (ToJsonResp a) => ToServer (Options a) where