Skip to content

Commit

Permalink
Respond with 500 Internal Server Error upon unhandled exceptions (#123)
Browse files Browse the repository at this point in the history
Refs #109
  • Loading branch information
akheron authored and cprussin committed Oct 9, 2018
1 parent 2f335e9 commit d333c6f
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/HTTPure/Server.purs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Prelude

import Effect as Effect
import Effect.Aff as Aff
import Control.Alt ((<|>))
import Data.Maybe as Maybe
import Data.Options ((:=), Options)
import Node.Encoding as Encoding
Expand All @@ -25,6 +26,14 @@ import HTTPure.Response as Response
-- | methods.
type ServerM = Effect.Effect (Effect.Effect Unit -> Effect.Effect Unit)

-- | Given a router, handle unhandled exceptions it raises by
-- | responding with 500 Internal Server Error.
onError500 :: (Request.Request -> Response.ResponseM) ->
Request.Request ->
Response.ResponseM
onError500 router request =
router request <|> Response.internalServerError ""

-- | This function takes a method which takes a `Request` and returns a
-- | `ResponseM`, an HTTP `Request`, and an HTTP `Response`. It runs the
-- | request, extracts the `Response` from the `ResponseM`, and sends the
Expand All @@ -35,7 +44,9 @@ handleRequest :: (Request.Request -> Response.ResponseM) ->
Effect.Effect Unit
handleRequest router request httpresponse =
void $ Aff.runAff (\_ -> pure unit) $
Request.fromHTTPRequest request >>= router >>= Response.send httpresponse
Request.fromHTTPRequest request
>>= onError500 router
>>= Response.send httpresponse

-- | Given a `ListenOptions` object, a function mapping `Request` to
-- | `ResponseM`, and a `ServerM` containing effects to run on boot, creates and
Expand Down
11 changes: 11 additions & 0 deletions test/Test/HTTPure/ServerSpec.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module Test.HTTPure.ServerSpec where
import Prelude

import Effect.Class as EffectClass
import Effect.Exception as Exception
import Control.Monad.Except as Except
import Data.Maybe as Maybe
import Data.Options ((:=))
import Data.String as String
Expand All @@ -23,6 +25,9 @@ import Test.HTTPure.TestHelpers ((?=))
mockRouter :: Request.Request -> Response.ResponseM
mockRouter { path } = Response.ok $ "/" <> String.joinWith "/" path

errorRouter :: Request.Request -> Response.ResponseM
errorRouter _ = Except.throwError $ Exception.error "fail!"

serveSpec :: TestHelpers.Test
serveSpec = Spec.describe "serve" do
Spec.it "boots a server on the given port" do
Expand All @@ -31,6 +36,12 @@ serveSpec = Spec.describe "serve" do
EffectClass.liftEffect $ close $ pure unit
out ?= "/test"

Spec.it "responds with a 500 upon unhandled exceptions" do
close <- EffectClass.liftEffect $ Server.serve 8080 errorRouter $ pure unit
status <- TestHelpers.getStatus 8080 Object.empty "/"
EffectClass.liftEffect $ close $ pure unit
status ?= 500

serve'Spec :: TestHelpers.Test
serve'Spec = Spec.describe "serve'" do
Spec.it "boots a server with the given options" do
Expand Down
7 changes: 7 additions & 0 deletions test/Test/HTTPure/TestHelpers.purs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ getHeader :: Int ->
getHeader port headers path header =
extractHeader header <$> request false port "GET" headers path ""

getStatus :: Int ->
Object.Object String ->
String ->
Aff.Aff Int
getStatus port headers path =
HTTPClient.statusCode <$> request false port "GET" headers path ""

-- | Mock an HTTP Request object
foreign import mockRequestImpl ::
String ->
Expand Down

0 comments on commit d333c6f

Please sign in to comment.