This project has MOVED to Codeberg, a non-profit community forge:
https://codeberg.org/valpackett/magicbane
https://codeberg.org/valpackett/magicbane
A web framework that integrates Servant, EKG, fast-logger, wai-cli… | now on https://codeberg.org/valpackett/magicbane
Home Page: https://codeberg.org/valpackett/magicbane
License: The Unlicense
This project has MOVED to Codeberg, a non-profit community forge:
https://codeberg.org/valpackett/magicbane
https://codeberg.org/valpackett/magicbane
In my application, I would like for the Wai Logger middleware to write a message to the log when an unhandled exception occurs and 500 response is sent to the client. For this to happen, it looks we need to catch that exception and respond inside our Application
. A basic example of how this would be done in servant is
app :: Application
app = serve api $ hoistServer api nt server
nt :: Handler a -> Handler a
nt = handleAny throwEx
where
throwEx e = throwError $ err500 {errBody = "The following server exception occured: " <> (cs $ show e)}
How can I do the same thing using magicbaneApp
? Or is this something magicbane could do?
• Overlapping instances for DefConfig SystemEnv
arising from a use of ‘gFromEnvCustom’
Matching instances:
instance data-default-class-0.1.2.0:Data.Default.Class.Default α =>
DefConfig α
-- Defined in ‘Magicbane’
instance DefConfig {redacted}
-- Defined at {redacted}
• In the expression:
gFromEnvCustom Option {dropPrefixCount = 1, customPrefix = ""}
In an equation for ‘fromEnv’:
fromEnv
= gFromEnvCustom Option {dropPrefixCount = 1, customPrefix = ""}
In the instance declaration for ‘FromEnv {redacted}’
This happens if Magicbane
is imported anywhere in the module's upstream dependency tree, even hiding everything; hooray for global instances. It's particularly disturbing that I have no idea where a Default
instance could have possibly come from for the type I'm trying to parse into.
In this case I'm able to work around it by only importing Magicbane.App
and Magicbane.HTTPClient
upstream. However, Default
is a widely-reviled antipattern and by preference I'd have it gone even if it didn't make things explode. On the other hand, killing it could cause significant downstream breakage.
Hi,
Trying to build the examples in stackage LTS-9.0 gives this error (for tiny.hs
, but I've also seen this with larger.hs
and an app I was working on):
> stack build
magicbane-examples-0.0.0: build (exe)
Preprocessing executable 'tiny' for magicbane-examples-0.0.0...
[1 of 1] Compiling Main ( tiny.hs, .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/tiny/tiny-tmp/Main.o )
/Users/ericrochester/tmp/magicbane/examples/tiny.hs:17:16: error:
• Couldn't match type ‘Handler’ with ‘ExceptT ServantErr IO’
arising from a functional dependency between:
constraint ‘servant-0.11:Servant.Utils.Enter.Enter
(BasicApp Text)
(MagicbaneApp BasicContext)
(ExceptT ServantErr IO)
(Handler Text)’
arising from a use of ‘magicbaneApp’
instance ‘servant-0.11:Servant.Utils.Enter.Enter (m a) m n (n a)’
at <no location info>
• In the second argument of ‘($)’, namely
‘magicbaneApp exampleAPI EmptyContext ctx hello’
In a stmt of a 'do' block:
defWaiMain $ magicbaneApp exampleAPI EmptyContext ctx hello
In the expression:
do { ctx <- newBasicContext;
defWaiMain $ magicbaneApp exampleAPI EmptyContext ctx hello }
-- While building package magicbane-examples-0.0.0 using:
/Users/ericrochester/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_1.24.2.0_ghc-8.0.2 --builddir=.stack-work/dist/x86_64-osx/Cabal-1.24.2.0 build exe:tiny --ghc-options " -ddump-hi -ddump-to-file"
Process exited with code: ExitFailure 1
For reference, package.yaml
looks like:
name: magicbane-examples
dependencies:
- base >=4.8.0.0 && <5
- magicbane
executables:
tiny:
main: tiny.hs
source-dirs: .
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
Should I be using magicbane from master branch instead of the release?
Thanks,
Eric
For Stackage Nightly:
Building library for magicbane-0.1.3..
[1 of 8] Compiling Magicbane.App ( library/Magicbane/App.hs, dist/build/Magicbane/App.o )
[2 of 8] Compiling Magicbane.Logging ( library/Magicbane/Logging.hs, dist/build/Magicbane/Logging.o )
[3 of 8] Compiling Magicbane.Metrics ( library/Magicbane/Metrics.hs, dist/build/Magicbane/Metrics.o )
[4 of 8] Compiling Magicbane.Util ( library/Magicbane/Util.hs, dist/build/Magicbane/Util.o )
[5 of 8] Compiling Magicbane.HTTPClient ( library/Magicbane/HTTPClient.hs, dist/build/Magicbane/HTTPClient.o )
library/Magicbane/HTTPClient.hs:13:1: error:
Could not find module ‘Control.Monad.Trans.Either’
Perhaps you meant
Control.Monad.Trans.Writer (from transformers-0.5.2.0)
Control.Monad.Trans.Error (from transformers-0.5.2.0)
Control.Monad.Trans.Reader (from transformers-0.5.2.0)
Use -v to see a list of the files searched for.
|
13 | import Control.Monad.Trans.Either
In the wake of #10, we now have:
Okay, what's MagicbaneApp?
newtype MagicbaneApp β α = MagicbaneApp {
unMagicbaneApp ∷ ReaderT β IO α }
It's just a ReaderT over IO!
This is exactly the RIO monad:
newtype RIO env a = RIO { unRIO :: ReaderT env IO a }
It would be nice to unify these!
I'm trying to build my project which references magicbane-0.4.0, but with extra-deps:
extra-deps:
- github: myfreeweb/wai-cli
commit: 6cdd4d03a538a16b7f94ea9fca79bdab0d103d35
in order to compile against latest wai-cli.
The stack build of magicbane is failing with:
/tmp/stack4749/magicbane-0.4.0/library/Magicbane.hs:13:3: error:
Conflicting exports for ‘host’:
‘module X’ exports ‘X.host’
imported from ‘Network.Wai.Cli’ at library/Magicbane.hs:32:1-51
‘module X’ exports ‘X.host’
imported from ‘Magicbane.HTTPClient’ at library/Magicbane.hs:39:1-42
(and originally defined in ‘http-client-0.5.14:Network.HTTP.Client.Types’)
Does it just need a hiding(host) in https://github.com/myfreeweb/magicbane/blob/master/library/Magicbane.hs#L32 ? Or am I trying to do something which isn't expected to work?
(the reason I'm trying to do this is I'm looking to put together a pull request for wai-cli to allow building on windows)
• Overlapping instances for HasLogFunc ModLogger
arising from a use of ‘logFuncL’
Matching instances:
instance Has ModLogger α => HasLogFunc α
-- Defined at /home/tejon/magicbane/library/Magicbane/Logging.hs:17:10
instance HasLogFunc LogFunc
-- Defined in ‘rio-0.1.3.0:RIO.Prelude.Logger’
I tried fixing this via Data.Type.Equality
:
instance ((α == ModLogger) ~ 'False, Has ModLogger α) ⇒ HasLogFunc α where
logFuncL = hasLens
But this doesn't work for reasons I haven't yet grasped. There's a procedural workaround described on Stack Overflow by @treeowl; I didn't immediately grok how to adapt it, and in any case it involves an additional class and newtype so I'd want your feedback on module style (per #12) before doing something like that.
In my init code, I wanted to use RIO's runSimpleApp
for some code that needs a logging environment, before I've built my application context - creating a sql connection pool wants a MonadLogger instance - and RIO doesn't export any function to write to console without a logger. But, I can't do that because there is an overlapping instance:
• Overlapping instances for HasLogFunc SimpleApp
arising from a use of ‘createPostgresqlPool’
Matching instances:
instance Has ModLogger α => HasLogFunc α
-- Defined in ‘Magicbane.Logging’
instance HasLogFunc SimpleApp -- Defined in ‘RIO.Prelude.Simple’
This is just a friendly suggestion meant to help you achieve your own goals.
Some pointers to this end:
https://www.gnu.org/licenses/gpl-faq.en.html#AssignCopyright
Some jurisdictions consider public domain IP, even from different nation-states, to be State property and charge license fees for using public domain IP
https://tldrlegal.com/license/bsd-3-clause-license-(revised)#fulltext
Particularly,
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
Hi, I'm new to Haskell and Magicbane seems like a really nice collection of things, especially to simplify adding some essentials to Servant - so thanks very much for the library!
However, I'm trying to use Magicbane with the latest Servant Server (0.18.1) and I'm getting the following compilation error:
servant-server > Registering library for servant-server-0.18.1..
magicbane > configure
magicbane > Configuring magicbane-0.4.1...
magicbane > build
magicbane > Preprocessing library for magicbane-0.4.1..
magicbane > Building library for magicbane-0.4.1..
magicbane > [ 1 of 10] Compiling Magicbane.App
magicbane >
magicbane > /tmp/stack-c4a82860c00c798d/magicbane-0.4.1/library/Magicbane/App.hs:22:37: error:
magicbane > • Could not deduce (HasContextEntry
magicbane > (ψ .++ DefaultErrorFormatters) ErrorFormatters)
magicbane > arising from a use of ‘serveWithContext’
magicbane > from the context: HasServer χ ψ
magicbane > bound by the type signature for:
magicbane > magicbaneApp :: forall β χ (ψ :: [*]).
magicbane > HasServer χ ψ =>
magicbane > Proxy χ -> Context ψ -> β -> ServerT χ (RIO β) -> Application
magicbane > at library/Magicbane/App.hs:21:1-104
magicbane > • In the expression: serveWithContext api sctx
magicbane > In the expression: serveWithContext api sctx $ srv ctx
magicbane > In an equation for ‘magicbaneApp’:
magicbane > magicbaneApp api sctx ctx actions
magicbane > = serveWithContext api sctx $ srv ctx
magicbane > where
magicbane > srv c
magicbane > = hoistServerWithContext
magicbane > api (Proxy @ψ) (runMagicbaneHandler c) actions
magicbane > |
magicbane > 22 | magicbaneApp api sctx ctx actions = serveWithContext api sctx $ srv ctx
magicbane > | ^^^^^^^^^^^^^^^^^^^^^^^^^
magicbane >
My reason for using a more recent version of Servant is so that I can implement custom parse errors for request inputs, as in https://docs.servant.dev/en/stable/cookbook/custom-errors/CustomErrors.html.
I realize I can probably just implement a custom FromJSON, but I was hoping for a neater solution, using Servant ErrorFormatters with Magicbane.
Can someone please suggest a workaround for this?
A recent PR fixed an issue with LTS 14.1. As part of the change-set for that fix this library's version was bumped to version 0.4.1
. However, when I ask stack
to include magicbane-0.4.1
it cannot be found on Hackage.
2019-09-10 12:53:49.510243: [error] Could not find magicbane-0.4.1 on Hackage
Possible candidates: magicbane-0.4.0@sha256:d47fc4467985283aa20dc538e14e05cccb06fa048c92f42afa391cfa19beee8b,2170.
Could you please check that magicbane-0.4.1
has been correctly published. It's entirely possible I'm not using the stack
tool correctly. Thanks.
An ops-minded coworker pointed out that this was missing from my Magicbane-powered requests. There should be some default, since a lot of APIs will reject any request without one.
Magicbane git master is now ExceptT-free. (More explanation in the 209cfbf commit message.) The new method of throwing errors is throwIO
.
Please test your applications!
/cc @tejon
I haven't investigated this a lot yet, but in my app, it looks like trying to use the env var-driven config is a recipe for build errors. I'm following along with the larger.hs
example. Removing the typeclass instance for DefConfig
results in a missing instance, having DefConfig
but no FromEnv
is fine (until you want to parse config from env vars), and having DefConfig
/FromEnv
without a definition for fromEnv
doesn't change the behavior.
I have not tried multiple LTS resolvers yet. If there's a particular resolver I should use, I'm open to suggestions. I also have not double-checked the official library's documentation. Even if there's relevant info in upstream documentation, we should work on making sure the examples compile for reasonably recent stack setups.
Here's a sample of what happens when compiling the example larger.hs
straight from this repository in my project (As close as I can easily get to a minimal, complete, verifiable example):
user@host ~/project $ stack ghc larger.hs
[1 of 1] Compiling Main ( larger.hs, larger.o )
larger.hs:18:13: error:
• Overlapping instances for DefConfig LargeAppConf
arising from a use of ‘gFromEnvCustom’
Matching instances:
instance Default α => DefConfig α -- Defined in ‘Magicbane’
instance DefConfig LargeAppConf -- Defined at larger.hs:12:10
• In the expression:
gFromEnvCustom
Option {dropPrefixCount = 0, customPrefix = "LARGEAPP"}
In an equation for ‘fromEnv’:
fromEnv
= gFromEnvCustom
Option {dropPrefixCount = 0, customPrefix = "LARGEAPP"}
In the instance declaration for ‘FromEnv LargeAppConf’
|
18 | fromEnv = gFromEnvCustom Option { dropPrefixCount = 0, customPrefix = "LARGEAPP" }
|
I'm familiar with basic Haskell, and very new to Magicbane (and all of its dependencies), but let me know if there's anything else I can do to help with this.
I keep running into issues arising from Has
, and especially its interplay with the concrete HasFoo
class idiom. Today this culminated in encountering a runtime loop on code that shouldn't even typecheck (trivial reproduction here). This has thoroughly convinced me that @snoyberg chose the more stable path with RIO
, and I've now fallen back to exclusively using HasFoo
(with the exception of one instance Has ModHttpClient AppEnv
since that's required to use the API).
As seen on the Stackage build server:
magicbane: BuildFailureException Process exited with ExitFailure 1: ./Setup build
[6 of 9] Compiling Magicbane.HTTPClient ( library/Magicbane/HTTPClient.hs, dist/
build/Magicbane/HTTPClient.o )
library/Magicbane/HTTPClient.hs:69:25: error:
• Could not deduce (unliftio-core-0.1.1.0:Control.Monad.IO.Unlift.MonadUnlif
tIO
μ)
arising from a use of ‘HCC.withResponse’
from the context: (MonadHTTP ψ μ, MonadCatch μ)
bound by the type signature for:
performWithFn :: forall ψ (μ :: * -> *) ι ρ.
(MonadHTTP ψ μ, MonadCatch μ) =>
(ConduitM ι ByteString μ () -> μ ρ)
-> Request -> ExceptT Text μ (Response ρ)
at library/Magicbane/HTTPClient.hs:67:1-122
Possible fix:
add (unliftio-core-0.1.1.0:Control.Monad.IO.Unlift.MonadUnliftIO
μ) to the context of
the type signature for:
performWithFn :: forall ψ (μ :: * -> *) ι ρ.
(MonadHTTP ψ μ, MonadCatch μ) =>
(ConduitM ι ByteString μ () -> μ ρ)
-> Request -> ExceptT Text μ (Response ρ)
• In the expression: HCC.withResponse req
In the second argument of ‘($)’, namely
‘HCC.withResponse req
$ \ res
-> do body <- fn $ responseBody res
return res {responseBody = body}’
In the second argument of ‘($)’, namely
‘tryAny
$ HCC.withResponse req
$ \ res
-> do body <- fn $ responseBody res
return res {responseBody = body}’
|
69 | res ← lift $ tryAny $ HCC.withResponse req $ \res → do
| ^^^^^^^^^^^^^^^^^^^^
I was able to reproduce locally like so:
stack unpack magicbane-0.2.0 && cd magicbane-0.2.0
edit stack.yaml # add the following stack.yaml
stack build
# stack.yaml
resolver: nightly-2018-03-10
extra-deps:
- servant-0.13
- servant-server-0.13
- http-types-0.12.1
- http-conduit-2.3.0
Given:
type EntitiesAPI = "entities"
:> Capture "objtype" Object
:> Capture "uuid" IdDynamic
:> EntityAPI
type EntityAPI
= Get '[JSON] APIResult
:<|> Capture "childtype" Text
:> Get '[JSON] APIResult
entitiesHandler obj uuid = getEntityAPI bare :<|> const (getEntityAPI full)
where
bare = EntityAPIRequest obj uuid False
full = EntityAPIRequest obj uuid True
getEntityAPI x = _
With Servant, I have the following types:
entitiesHandler :: Server EntitiesAPI
getEntityAPI :: EntityAPIRequest -> Handler APIResult
With Magicbane, they become:
entitiesHandler :: Object -> IdDynamic -> MyApp APIResult :<|> (Text -> MyApp APIResult)
getEntityAPI :: EntityAPIRequest -> MyApp APIResult
The latter may not be a problem (I haven't directly hit an issue with it, but the change seems notable). The former, however, has some nasty implications. This will eventually be only one part of the API. I also have:
type MyAPI
= EntitiesAPI
-- more here later
api
= entitiesHandler
-- More here later
The comparative types of api
are:
api :: Server MyAPI
-- vs. --
api :: Object -> IdDynamic -> MyApp APIResult :<|> (Text -> MyApp APIResult)
That looks like it's going to become a nightmare as I fill out the API. I noticed that the examples mostly just don't have type annotations, but I'm working in a team environment and they're not something I want to give up. Is there a path forward from here?
RIO exports Data.String.fromString
(IsString
typeclass member). Magicbane currently exports Data.String.Conversions.Monomorphic.fromString
, a type-constrained alias for Data.String.Conversions.cs
. As all of the types supported by the latter have IsString
instances, I don't believe there is any benefit in providing the non-base
version.
I have a PR ready to address this but today's GitHub issues are currently preventing me from pushing it.
Magicbane asserts Snoyman's classy-prelude
. With the recent reveal of RIO
, and Snoyman on board that project, it may be worth considering the benefits/logistics of moving to it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.