minion-conduit (empty) → 0.1.0.0
raw patch · 8 files changed
+238/−0 lines, 8 filesdep +basedep +binarydep +bytestring
Dependencies added: base, binary, bytestring, conduit, http-types, minion, minion-conduit, text, wai, warp
Files
- LICENSE +20/−0
- README.md +45/−0
- app/UpperCase.hs +7/−0
- minion-conduit.cabal +82/−0
- src/Web/Minion/Conduit.hs +4/−0
- src/Web/Minion/Examples/Conduit/UpperCase.hs +25/−0
- src/Web/Minion/Request/Conduit.hs +35/−0
- src/Web/Minion/Response/Conduit.hs +20/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2024 goosedb++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,45 @@+# Minion++Minion is Haskell library for developing web applications. It stands between [Scotty](https://hackage.haskell.org/package/scotty) and [Servant](https://hackage.haskell.org/package/servant-server) ++| | Scotty | Minion | Servant |+| ---------------- | ------ | ------ | ------- |+| As simple as ABC | Yes | No | No |+| At term level | Yes | Yes | No |+| Typesafe | No | Yes | Yes |+| Introspectable | No | Yes | Yes |+| Generated client | No | No | Yes |++ +Since Minion defines servers at the term level, it's easier to start and without excess verbosity.++```haskell+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+module Main where++import Web.Minion+import Network.Wai.Handler.Warp qualified as Warp++main :: IO ()+main = Warp.run 9001 app++app :: ApplicationM IO+app = serve api ++api :: Router Void IO+api = "api" /> + [ "about" /> handlePlainText @String GET (pure "Hello-World Minion server")+ , "hello" /> capture @String "name" + .> handlePlainText @String GET (\name -> pure $ "Hello, " <> name <> "!")+ ]+```++Documentation and examples can be found on [Hackage](https://hackage.haskell.org/package/minion) ++Minion ecosystem also contains following libraries:+* [minion-conduit](https://hackage.haskell.org/package/minion-conduit) +* [minion-htmx](https://hackage.haskell.org/package/minion-htmx) +* [minion-jwt](https://hackage.haskell.org/package/minion-jwt) +* [minion-wai-extra](https://hackage.haskell.org/package/minion-wai-extra) +* [minion-openapi3](https://hackage.haskell.org/package/minion-openapi3)
+ app/UpperCase.hs view
@@ -0,0 +1,7 @@+module Main where++import Network.Wai.Handler.Warp qualified as Warp+import Web.Minion.Examples.Conduit.UpperCase++main :: IO ()+main = Warp.run 9001 Web.Minion.Examples.Conduit.UpperCase.app
+ minion-conduit.cabal view
@@ -0,0 +1,82 @@+cabal-version: 3.0+name: minion-conduit+version: 0.1.0.0+license: MIT+license-file: LICENSE+author: goosedb+synopsis: Minion conduit support+maintainer: goosedb@yandex.ru+category: Web+build-type: Simple+extra-source-files: README.md++common common+ ghc-options: -Wall+ default-extensions:+ AllowAmbiguousTypes+ BlockArguments+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveAnyClass+ DeriveGeneric+ DerivingStrategies+ DerivingStrategies+ DuplicateRecordFields+ DuplicateRecordFields+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ MultiParamTypeClasses+ NamedFieldPuns+ OverloadedLists+ OverloadedRecordDot+ OverloadedRecordDot+ OverloadedStrings+ PolyKinds+ RankNTypes+ RecordWildCards+ RoleAnnotations+ ScopedTypeVariables+ TypeApplications+ TypeFamilies+ TypeOperators+ UndecidableInstances+ ViewPatterns++library+ import: common+ exposed-modules:+ Web.Minion.Conduit+ Web.Minion.Examples.Conduit.UpperCase+ Web.Minion.Request.Conduit+ Web.Minion.Response.Conduit++ build-depends:+ , base >= 4.16 && < 5+ , binary+ , bytestring+ , conduit+ , http-types+ , minion+ , text+ , wai++ hs-source-dirs: src+ default-language: Haskell2010++executable minion-conduit-example+ import: common+ main-is: UpperCase.hs+ build-depends:+ , base+ , minion-conduit+ , warp++ hs-source-dirs: app+ default-language: Haskell2010+ ghc-options: -threaded
+ src/Web/Minion/Conduit.hs view
@@ -0,0 +1,4 @@+module Web.Minion.Conduit (streamBody, streamBodyBytes, ConduitResponse (..), ConduitRequest (..)) where++import Web.Minion.Request.Conduit+import Web.Minion.Response.Conduit (ConduitResponse (..))
+ src/Web/Minion/Examples/Conduit/UpperCase.hs view
@@ -0,0 +1,25 @@+module Web.Minion.Examples.Conduit.UpperCase (app) where++import Data.Binary.Put qualified as Binary+import Data.Conduit ((.|))+import Data.Conduit.Combinators qualified as Conduit+import Data.Functor (($>))+import Data.Text qualified as Text+import Data.Text.IO qualified as Text.IO+import Web.Minion+import Web.Minion.Conduit++app :: ApplicationM IO+app = serve api++api :: Router Void IO+api = "api" /> "conduit" /> streamBodyBytes .> handle POST upperCase++upperCase :: ConduitRequest IO -> IO ConduitResponse+upperCase (ConduitRequest source) = pure $ ConduitResponse do+ source+ .| Conduit.decodeUtf8+ .| Conduit.map Text.toUpper+ .| Conduit.mapM (\a -> Text.IO.putStrLn a $> a)+ .| Conduit.encodeUtf8+ .| Conduit.map (Binary.execPut . Binary.putByteString)
+ src/Web/Minion/Request/Conduit.hs view
@@ -0,0 +1,35 @@+module Web.Minion.Request.Conduit (ConduitRequest (..), streamBody, streamBodyBytes) where++import Control.Monad.IO.Class (MonadIO (..))+import Data.ByteString qualified as Bytes+import Data.Conduit qualified as C+import Data.Conduit.Combinators qualified as C+import Network.Wai qualified as Wai+import Web.Minion.Args (WithReq)+import Web.Minion.Introspect qualified as I+import Web.Minion.Request+import Web.Minion.Router++newtype ConduitRequest m = ConduitRequest (C.ConduitT () Bytes.ByteString m ())++instance IsRequest (ConduitRequest m) where+ type RequestValue (ConduitRequest m) = ConduitRequest m+ getRequestValue = id++{-# INLINE streamBody #-}+streamBody ::+ forall req m i ts.+ (MonadIO m, IsRequest req, I.Introspection i I.Request req) =>+ (ConduitRequest m -> req) ->+ ValueCombinator i (WithReq m req) ts m+streamBody transform = Request \_ -> pure . transform . ConduitRequest . readReq++{-# INLINE streamBodyBytes #-}+streamBodyBytes ::+ forall m i ts.+ (MonadIO m, I.Introspection i I.Request (ConduitRequest m)) =>+ ValueCombinator i (WithReq m (ConduitRequest m)) ts m+streamBodyBytes = Request \_ -> pure . ConduitRequest . readReq++readReq :: (MonadIO m) => Wai.Request -> C.ConduitT i Bytes.ByteString m ()+readReq req = C.repeatWhileM (liftIO $ Wai.getRequestBodyChunk req) (not . Bytes.null)
+ src/Web/Minion/Response/Conduit.hs view
@@ -0,0 +1,20 @@+module Web.Minion.Response.Conduit where++import Conduit qualified as C+import Control.Monad ((>=>))+import Data.ByteString.Builder qualified as Data.ByteString+import Data.Conduit.Combinators qualified as C+import Network.HTTP.Types qualified as Http+import Network.Wai qualified as Wai+import Web.Minion.Response++newtype ConduitResponse = ConduitResponse (C.ConduitT () Data.ByteString.Builder IO ())++instance (Monad m) => ToResponse m ConduitResponse where+ toResponse _ (ConduitResponse c) = pure $ Wai.responseStream+ Http.status200+ []+ \write flush -> C.runConduit $ c C..| C.mapM_ (write >=> const flush) C..| C.sinkNull++instance CanRespond ConduitResponse where+ canRespond _ = True