cookbook: add jsonerror section

This commit is contained in:
Domen Kožar 2018-04-17 15:25:38 +01:00
parent 6af38354d0
commit 9b73435d21
No known key found for this signature in database
GPG key ID: C2FFBCAFD2C24246
4 changed files with 76 additions and 0 deletions

View file

@ -5,6 +5,7 @@ packages:
using-custom-monad/ using-custom-monad/
jwt-and-basic-auth/ jwt-and-basic-auth/
file-upload/ file-upload/
jsonerror/
structuring-apis/ structuring-apis/
https/ https/
pagination/ pagination/

View file

@ -26,3 +26,4 @@ you name it!
jwt-and-basic-auth/JWTAndBasicAuth.lhs jwt-and-basic-auth/JWTAndBasicAuth.lhs
file-upload/FileUpload.lhs file-upload/FileUpload.lhs
pagination/Pagination.lhs pagination/Pagination.lhs
jsonerror/Jsonerror.lhs

View file

@ -0,0 +1,50 @@
# HTTP 4XX/5XX errors with JSON body
Common RESTful design pattern is to return
HTTP 4XX or 5XX errors with JSON as body content.
Servant offer such support via `MonadError` instance:
```haskell
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
import Servant
import GHC.Generics (Generic)
import Data.Aeson (ToJSON, encode)
import Data.Text (Text)
import Network.HTTP.Types (hContentType)
import Control.Monad.Except (MonadError)
throwJSONError :: (MonadError ServantErr m, ToJSON a) => ServantErr -> a -> m b
throwJSONError err json = throwError $ err
{ errBody = encode json
, errHeaders = [ jsonHeader ]
}
where
jsonHeader = ( hContentType
, "application/json;charset=utf-8" )
```
And simple usage with servant-server:
```haskell
data JSONError = JSONError
{ error :: Text
} deriving (Generic, ToJSON)
handler :: Handler NoContent
handler = throwJSONError err400 $ JSONError "test"
main :: IO ()
main = undefined
```
There are (at least) two shortcomings with this approach:
1) [throwError sacrifices content negotiation](https://github.com/haskell-servant/servant/issues/732)
2) Errors are not part of the type-level API safety, there are solutions like [servant-checked-exceptions](https://github.com/cdepillabout/servant-checked-exceptions) but they don't implement all HasServer, etc instances.

View file

@ -0,0 +1,24 @@
name: cookbook-jsonerror
version: 0.1
synopsis: Jsonerror with Servant example
homepage: http://haskell-servant.readthedocs.org/
license: BSD3
author: Servant Contributors
maintainer: haskell-servant-maintainers@googlegroups.com
build-type: Simple
cabal-version: >=1.10
executable cookbook-jsonerror
if impl(ghc < 7.10.1)
buildable: False
main-is: Jsonerror.lhs
build-depends: base == 4.*
, aeson
, servant
, servant-server
, http-types
, mtl
, text
default-language: Haskell2010
ghc-options: -Wall -pgmL markdown-unlit
build-tool-depends: markdown-unlit:markdown-unlit