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 Control.Monad.Eff.Class as EffClass
import Data.StrMap as StrMap
import Test.Spec as Spec
import Test.Spec.Assertions as Assertions
import HTTPure.SpecHelpers as SpecHelpers
import Headers as Headers
import HelloWorld as HelloWorld
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 = Spec.it "runs the hello world example" do
EffClass.liftEff HelloWorld.main
response <- SpecHelpers.get "http://localhost:8080"
response <- SpecHelpers.get 8080 StrMap.empty "/"
response `Assertions.shouldEqual` "hello world!"
multiRouteSpec :: SpecHelpers.Test
multiRouteSpec = Spec.it "runs the multi route example" do
EffClass.liftEff MultiRoute.main
hello <- SpecHelpers.get "http://localhost:8081/hello"
hello <- SpecHelpers.get 8081 StrMap.empty "/hello"
hello `Assertions.shouldEqual` "hello"
goodbye <- SpecHelpers.get "http://localhost:8081/goodbye"
goodbye <- SpecHelpers.get 8081 StrMap.empty "/goodbye"
goodbye `Assertions.shouldEqual` "goodbye"
headersSpec :: SpecHelpers.Test
headersSpec = Spec.it "runs the headers example" do
EffClass.liftEff Headers.main
header <- SpecHelpers.getHeader "http://localhost:8082" "X-Example"
header `Assertions.shouldEqual` "hello world!"
postSpec :: SpecHelpers.Test
postSpec = Spec.it "runs the post example" do
EffClass.liftEff Post.main
response <- SpecHelpers.post 8084 StrMap.empty "/" "test"
response `Assertions.shouldEqual` "test"
integrationSpec :: SpecHelpers.Test
integrationSpec = Spec.describe "Integration" do
headersSpec
helloWorldSpec
multiRouteSpec
headersSpec
postSpec

View File

@ -21,7 +21,7 @@ serveSpec :: SpecHelpers.Test
serveSpec = Spec.describe "serve" do
Spec.it "boots a server on the given port" do
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"
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.ST as ST
import Data.Maybe as Maybe
import Data.Options as Options
import Data.String as StringUtil
import Data.StrMap as StrMap
import Node.Encoding as Encoding
@ -40,19 +41,29 @@ type Test = Spec.Spec TestEffects Unit
-- | The type for the entire test suite.
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
-- | client request.
getResponse :: forall e.
String ->
Aff.Aff (http :: HTTP.HTTP | e) HTTPClient.Response
getResponse url = Aff.makeAff \_ success ->
HTTPClient.requestFromURI url success >>= endRequest
request :: forall e.
Int ->
String ->
StrMap.StrMap String ->
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
-- | 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
-- | string with the response body.
get :: forall e. String -> Aff.Aff (HTTPRequestEffects e) String
get url = getResponse url >>= toString
get :: forall e.
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
-- | 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
-- | string with the header value for the given header.
getHeader :: forall e.
Int ->
StrMap.StrMap String ->
String ->
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
foreign import data MOCK_REQUEST :: Eff.Effect