Skip to content

Incompatibility between servant-server and Vanilla JS generator on server-side errors #296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
utdemir opened this issue Dec 16, 2015 · 9 comments

Comments

@utdemir
Copy link

utdemir commented Dec 16, 2015

Hi.

When any endpoint on servant-server returns a ServantErr, it just puts the errBody as is. But the JS client generated with servant-js expects a JSON object and tries to decode it; then it fails with a syntax error.

I think either the server should encode the errors conforming with Content-type, or generated JavaScript client must not convert it from JSON and just give the response body to error callback.

Example:

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators     #-}

module Main where

--------------------------------------------------------------------------------                                                                  
import           Control.Monad.Except
import           Control.Monad.Trans.Class
import           Data.Proxy
import           Data.Text
import           Network.Wai.Handler.Warp
import           Servant
import           Servant.JS
--------------------------------------------------------------------------------                                                              
type API = "stuff" :> Get '[JSON] ()

api :: Proxy API
api = Proxy

server :: Server API
server = throwError $ err500 { errBody="not possible" }

main :: IO ()
main = do
  putStrLn . unpack $ jsForAPI api vanillaJS
  run 2222 $ serve api server

When calling the API with generated JavaScript, instead of calling the error handler, it fails with syntax error.

2015-12-16-144902_635x380_scrot

@utdemir utdemir changed the title Incompatibility between servant-server on Vanilla JS generator on server-side errors Incompatibility between servant-server and Vanilla JS generator on server-side errors Dec 16, 2015
@arianvp
Copy link
Member

arianvp commented Dec 16, 2015

Edit: Moved this comment to #294

@utdemir
Copy link
Author

utdemir commented Dec 16, 2015

@arianvp I guess you wrote this for #294 .

@gasi
Copy link
Contributor

gasi commented Dec 16, 2015

Relating to this, is there a way to return JSON encodable errors using ServantErr? Based on the tutorial, it seems like ServantErr always has a string based errBody which is not how most APIs are built 😄

@arianvp
Copy link
Member

arianvp commented Dec 16, 2015

Something like


data ServantErr e = ServantErr { errHTTPCode     :: Int
                               , errReasonPhrase :: String
                               , errBody         ::  e
                               , errHeaders      :: [HTTP.Header]
                               }  deriving (Show, Eq, Read)

Such that e can only be a value that corresponds to values that are accepted by the MimeRender instance of the resource? Yes I think this would be extremely useful.

I don't think it would be too hard to implement. Right?

@gasi
Copy link
Contributor

gasi commented Dec 16, 2015

Yes, that looks great, @arianvp. To clarify, does MimeRender refer to the following?

type UserAPI = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
                                                            ^^^^^^^^^^^^^^

I’d give it a shot to implement but I am still a beginner Haskell programmer. Happy to help in other ways though: I have quite a bit of experience building REST APIs with other languages, so I can share that and could also help out with docs, etc. Let me know.

@jkarni
Copy link
Member

jkarni commented Dec 16, 2015

I'm not entirely sure we could have a fully polymorphic e, but if we can't, then:

data ServantErr cts = forall e. AllMimeRender e cts => 
               ServantErr { errHTTPCode     :: Int
                          , errReasonPhrase :: String
                          , errBody         :: e
                          , errHeaders      :: [HTTP.Header]
                          }  deriving (Show, Eq, Read)

@gasi
Copy link
Contributor

gasi commented Dec 16, 2015

REST API error handling:

{
  "error": {
    "message": "Message describing the error",
    "type": "OAuthException",
    "code": 190,
    "error_subcode": 460,
    "error_user_title": "A title",
    "error_user_msg": "A message",
    "fbtrace_id": "EJplcsCHuLu"
  }
}
{
  "errors": [
    {
      "message": "Sorry, that page does not exist",
      "code": 34
    }
  ]
}

@arianvp
Copy link
Member

arianvp commented Dec 17, 2015

@gasi Yes it does. Check out the tutorial, it explains how JSON relates to MimeRender http://haskell-servant.github.io/tutorial/server.html#using-content-types-with-your-data-types

@gasi
Copy link
Contributor

gasi commented Dec 18, 2015

@arianvp 👍 I’ll check it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants