Add post example (#41)

This commit is contained in:
Connor Prussin 2017-07-18 10:09:03 -07:00 committed by GitHub
parent 4ca1378f7d
commit b8169e4fdb
5 changed files with 105 additions and 25 deletions

View File

@ -0,0 +1,10 @@
# Post Example
This is a basic example of handling a Post. It will respond to a HTTP POST on
any path with the post body in the response body.
To run the example server, run:
```bash
make example EXAMPLE=Post
```

View File

@ -0,0 +1,31 @@
module Post where
import Prelude
import Control.Monad.Eff.Console as Console
import Data.StrMap as StrMap
import HTTPure as HTTPure
-- | Serve the example server on this port
port :: Int
port = 8084
-- | Shortcut for `show port`
portS :: String
portS = show port
-- | Route to the correct handler
router :: forall e. HTTPure.Request -> HTTPure.ResponseM e
router (HTTPure.Post _ _ body) = pure $ HTTPure.OK StrMap.empty body
router _ = pure $ HTTPure.OK StrMap.empty ""
-- | Boot up the server
main :: forall e. HTTPure.ServerM (console :: Console.CONSOLE | e)
main = HTTPure.serve port router do
Console.log $ " ┌───────────────────────────────────────────┐"
Console.log $ " │ Server now up on port " <> portS <> ""
Console.log $ " │ │"
Console.log $ " │ To test, run: │"
Console.log $ " │ > curl -XPOST --data test localhost:" <> portS <> ""
Console.log $ " │ # => test │"
Console.log $ " └───────────────────────────────────────────┘"

View File

@ -3,37 +3,48 @@ module HTTPure.IntegrationSpec where
import Prelude import Prelude
import Control.Monad.Eff.Class as EffClass import Control.Monad.Eff.Class as EffClass
import Data.StrMap as StrMap
import Test.Spec as Spec import Test.Spec as Spec
import Test.Spec.Assertions as Assertions import Test.Spec.Assertions as Assertions
import HTTPure.SpecHelpers as SpecHelpers import HTTPure.SpecHelpers as SpecHelpers
import Headers as Headers
import HelloWorld as HelloWorld import HelloWorld as HelloWorld
import MultiRoute as MultiRoute import MultiRoute as MultiRoute
import Headers as Headers import Post as Post
headersSpec :: SpecHelpers.Test
headersSpec = Spec.it "runs the headers example" do
EffClass.liftEff Headers.main
header <- SpecHelpers.getHeader 8082 StrMap.empty "/" "X-Example"
header `Assertions.shouldEqual` "hello world!"
response <- SpecHelpers.get 8082 (StrMap.singleton "X-Input" "test") "/"
response `Assertions.shouldEqual` "test"
helloWorldSpec :: SpecHelpers.Test helloWorldSpec :: SpecHelpers.Test
helloWorldSpec = Spec.it "runs the hello world example" do helloWorldSpec = Spec.it "runs the hello world example" do
EffClass.liftEff HelloWorld.main EffClass.liftEff HelloWorld.main
response <- SpecHelpers.get "http://localhost:8080" response <- SpecHelpers.get 8080 StrMap.empty "/"
response `Assertions.shouldEqual` "hello world!" response `Assertions.shouldEqual` "hello world!"
multiRouteSpec :: SpecHelpers.Test multiRouteSpec :: SpecHelpers.Test
multiRouteSpec = Spec.it "runs the multi route example" do multiRouteSpec = Spec.it "runs the multi route example" do
EffClass.liftEff MultiRoute.main EffClass.liftEff MultiRoute.main
hello <- SpecHelpers.get "http://localhost:8081/hello" hello <- SpecHelpers.get 8081 StrMap.empty "/hello"
hello `Assertions.shouldEqual` "hello" hello `Assertions.shouldEqual` "hello"
goodbye <- SpecHelpers.get "http://localhost:8081/goodbye" goodbye <- SpecHelpers.get 8081 StrMap.empty "/goodbye"
goodbye `Assertions.shouldEqual` "goodbye" goodbye `Assertions.shouldEqual` "goodbye"
headersSpec :: SpecHelpers.Test postSpec :: SpecHelpers.Test
headersSpec = Spec.it "runs the headers example" do postSpec = Spec.it "runs the post example" do
EffClass.liftEff Headers.main EffClass.liftEff Post.main
header <- SpecHelpers.getHeader "http://localhost:8082" "X-Example" response <- SpecHelpers.post 8084 StrMap.empty "/" "test"
header `Assertions.shouldEqual` "hello world!" response `Assertions.shouldEqual` "test"
integrationSpec :: SpecHelpers.Test integrationSpec :: SpecHelpers.Test
integrationSpec = Spec.describe "Integration" do integrationSpec = Spec.describe "Integration" do
headersSpec
helloWorldSpec helloWorldSpec
multiRouteSpec multiRouteSpec
headersSpec postSpec

View File

@ -21,7 +21,7 @@ serveSpec :: SpecHelpers.Test
serveSpec = Spec.describe "serve" do serveSpec = Spec.describe "serve" do
Spec.it "boots a server on the given port" do Spec.it "boots a server on the given port" do
EffClass.liftEff $ Server.serve 7901 mockRouter $ pure unit EffClass.liftEff $ Server.serve 7901 mockRouter $ pure unit
out <- SpecHelpers.get "http://localhost:7901/test" out <- SpecHelpers.get 7901 StrMap.empty "/test"
out `Assertions.shouldEqual` "/test" out `Assertions.shouldEqual` "/test"
serverSpec :: SpecHelpers.Test serverSpec :: SpecHelpers.Test

View File

@ -7,6 +7,7 @@ import Control.Monad.Eff as Eff
import Control.Monad.Eff.Exception as Exception import Control.Monad.Eff.Exception as Exception
import Control.Monad.ST as ST import Control.Monad.ST as ST
import Data.Maybe as Maybe import Data.Maybe as Maybe
import Data.Options as Options
import Data.String as StringUtil import Data.String as StringUtil
import Data.StrMap as StrMap import Data.StrMap as StrMap
import Node.Encoding as Encoding import Node.Encoding as Encoding
@ -40,19 +41,29 @@ type Test = Spec.Spec TestEffects Unit
-- | The type for the entire test suite. -- | The type for the entire test suite.
type TestSuite = Eff.Eff TestEffects Unit type TestSuite = Eff.Eff TestEffects Unit
-- | Given an HTTPClient.Request, close the request stream so the request can be
-- | fired.
endRequest :: forall e.
HTTPClient.Request -> Eff.Eff (http :: HTTP.HTTP | e) Unit
endRequest request = Stream.end (HTTPClient.requestAsStream request) $ pure unit
-- | Given a URL, a failure handler, and a success handler, create an HTTP -- | Given a URL, a failure handler, and a success handler, create an HTTP
-- | client request. -- | client request.
getResponse :: forall e. request :: forall e.
String -> Int ->
Aff.Aff (http :: HTTP.HTTP | e) HTTPClient.Response String ->
getResponse url = Aff.makeAff \_ success -> StrMap.StrMap String ->
HTTPClient.requestFromURI url success >>= endRequest String ->
String ->
Aff.Aff (http :: HTTP.HTTP | e) HTTPClient.Response
request port method headers path body = Aff.makeAff \_ success -> do
req <- HTTPClient.request options success
let stream = HTTPClient.requestAsStream req
_ <- Stream.writeString stream Encoding.UTF8 body noop
Stream.end stream noop
noop
where
noop = pure unit
options =
HTTPClient.method `Options.assoc` method <>
HTTPClient.hostname `Options.assoc` "localhost" <>
HTTPClient.port `Options.assoc` port <>
HTTPClient.path `Options.assoc` path <>
HTTPClient.headers `Options.assoc` HTTPClient.RequestHeaders headers
-- | Given an ST String buffer and a new string, concatenate that new string -- | Given an ST String buffer and a new string, concatenate that new string
-- | onto the ST buffer. -- | onto the ST buffer.
@ -71,8 +82,22 @@ toString response = Aff.makeAff \_ success -> do
-- | Run an HTTP GET with the given url and return an Aff that contains the -- | Run an HTTP GET with the given url and return an Aff that contains the
-- | string with the response body. -- | string with the response body.
get :: forall e. String -> Aff.Aff (HTTPRequestEffects e) String get :: forall e.
get url = getResponse url >>= toString Int ->
StrMap.StrMap String ->
String ->
Aff.Aff (HTTPRequestEffects e) String
get port headers path = request port "GET" headers path "" >>= toString
-- | Run an HTTP POST with the given url and body and return an Aff that
-- | contains the string with the response body.
post :: forall e.
Int ->
StrMap.StrMap String ->
String ->
String ->
Aff.Aff (HTTPRequestEffects e) String
post port headers path body = request port "POST" headers path body >>= toString
-- | Convert a request to an Aff containing the string with the given header -- | Convert a request to an Aff containing the string with the given header
-- | value. -- | value.
@ -85,10 +110,13 @@ extractHeader header = unmaybe <<< lookup <<< HTTPClient.responseHeaders
-- | Run an HTTP GET with the given url and return an Aff that contains the -- | Run an HTTP GET with the given url and return an Aff that contains the
-- | string with the header value for the given header. -- | string with the header value for the given header.
getHeader :: forall e. getHeader :: forall e.
Int ->
StrMap.StrMap String ->
String -> String ->
String -> String ->
Aff.Aff (HTTPRequestEffects e) String Aff.Aff (HTTPRequestEffects e) String
getHeader url header = extractHeader header <$> getResponse url getHeader port headers path header =
extractHeader header <$> request port "GET" headers path ""
-- | An effect encapsulating creating a mock request object -- | An effect encapsulating creating a mock request object
foreign import data MOCK_REQUEST :: Eff.Effect foreign import data MOCK_REQUEST :: Eff.Effect