packages feed

gingersnap 0.2.0.0 → 0.2.0.1

raw patch · 3 files changed

+73/−16 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

README.md view
@@ -23,6 +23,7 @@  -- For our automatic JSON instance: import GHC.Generics (Generic) import Gingersnap.Core+import Network.HTTP.Types.Status (internalServerError500) import Snap.Core -- From the 'snap-server' package: import Snap.Http.Server (quickHttpServe)@@ -82,6 +83,7 @@    quickHttpServe $ route [         ("one", one ctx)       , ("two", two ctx)+      , ("three", three ctx)       ] ``` @@ -158,13 +160,62 @@     only roll back if there's an exception, and in contrast to manually beginning     a transaction, which provides no check that we properly commit or rollback     (e.g. we could forget to commit/rollback in one case among many in a complicated-    statement)+    branching expression) +## Not everything's rspGood +What if we don't want to send a successful ok200 message? Or maybe we don't even+want to commit our transaction? These might come in handy then:++    rspBadCommit :: ApiErr ae => ae -> Rsp+    rspBadRollback :: ApiErr ae => ae -> Rsp++(`rspBad` is an alias for `rspBadRollback`)++`ApiErr` is a simple typeclass that ensures our error type can be converted to+a HTTP status code and JSON value.++We don't need to (and won't be) exploring the `ApiErr` typeclass here directly+, since we've got a good default instance with the `DefaultApiErr` type.++```haskell+three :: Ctx -> Snap ()+three ctx =+   inTransaction ctx $ \conn -> do+      [Only d] <- query_ conn " SELECT random () "+      pure $ if d >= (0.5 :: Double)+         then rspGood d+         else rspBad $ DefaultApiErr_Custom internalServerError500 $+            "number too small: "++ show d+```++    $ curl -v 'localhost:8000/three'+    [...]+    < HTTP/1.1 500 Internal Server Error+    [...]+    {"errorCode":6,"errorVals":[],"errorMessage":"number too small: 0.163489528931677"}+    $ curl -v 'localhost:8000/three'+    [...]+    < HTTP/1.1 200 OK+    [...]+    {"result":0.594665706157684}++If you'd like to write your own `ApiErr` instance (which you probably should if+you're building something "real":+  - The definition of "errResult" for "DefaultApiErr" might be a good guide+    for how to get a consistent JSON result.+  - You'll want to make that type the "CtxErrType" associated type for IsCtx++## Not everything's JSON++A JSON API is usually JSON but if you'd like to e.g. send a CSV or a file there+are functions like `rspGoodCSV` and (the most general) `rspGoodLBS`.++If you don't see a function you need it's easy to define your own.+ ## Other things to discover  This tutorial is a work in progress, and these'll be the next concepts to be touched on: -  - "Not everything's rspGood": rspBadRollback, ApiErr, and others-  - reqObject and (.!) for consuming JSON+  - reqObject and (.!) for receiving JSON
gingersnap.cabal view
@@ -1,5 +1,5 @@ name:                gingersnap-version:             0.2.0.0+version:             0.2.0.1 synopsis:            snap-core + aeson + postgresql-simple = delicious description:   JSON API idioms for snap-core, preventing DB connection leaks.
src/Gingersnap/Core.hs view
@@ -25,20 +25,28 @@     -- * DB Transactions    , inTransaction+   , inTransactionMode    , inTransaction_readOnly    , inTransaction_override-   , inTransactionMode    , rspIsGood     -- * IsCtx    , IsCtx(..) +   -- * JSON requests+   , reqObject+   , reqObject'+   , (.!)+   , (.!?)+   , ReqObject(..)+    -- * Errors+   , errorEarlyCode+    , ApiErr(..)    , ErrResult(..)    , DefaultApiErr(..) -   , errorEarlyCode    , ctxErr     -- * Internals@@ -47,12 +55,6 @@    , RspPayload(..)    , ShouldCommitOrRollback(..) -   , reqObject-   , reqObject'-   , (.!)-   , (.!?)-   , ReqObject(..)-    -- * Reexports, for convenience    , Pool    , createPool@@ -105,8 +107,8 @@    errResult :: apiErr -> ErrResult     -- | The request object is missing a required key.-   --   E.g. the request is {"first": "Tom"} but we need both a "first" and a-   --   "last"+   --   E.g. the request is @{"first": "Tom"}@ but we need both a @"first"@ and a+   --   @"last"@    apiErr_missingRequestKey :: Text -> apiErr     -- | We can't process the request because the request is malformed JSON or@@ -290,8 +292,8 @@ inTransaction ctx actionThatReturnsAnRsp = do    inTransactionMode ctx PSQL.Serializable PSQL.ReadWrite actionThatReturnsAnRsp --- | An endpoint that uses 'inTransaction_readOnly' will keep responding even---   when the server is in read-only mode.+-- | Creates a read-only transaction and will keep responding even if the+--   server's in read-only mode. --  --   Note that you the programmer are asserting the DB queries are read-only. --   There's nothing in this library or in postgresql-simple which statically@@ -312,6 +314,10 @@ inTransaction_override ctx action =    inTransaction_internal ctx PSQL.Serializable PSQL.ReadWrite action +-- | The most general version of 'inTransaction'.+-- +--   An endpoint that uses 'ReadOnly' will keep responding even when the server+--   is in read-only mode. inTransactionMode :: IsCtx ctx => ctx -> PSQL.IsolationLevel -> PSQL.ReadWriteMode -> (Connection -> IO Rsp) -> Snap () inTransactionMode ctx isolationLevel' readWriteMode' actionThatReturnsAResponse = do    readOnlyMode <- liftIO $ ctxGetReadOnlyMode ctx