Skip to content

Commit

Permalink
Add client module
Browse files Browse the repository at this point in the history
  • Loading branch information
paf31 committed Sep 28, 2015
1 parent 0bf5bf5 commit 2fb1e83
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 8 deletions.
7 changes: 4 additions & 3 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@
"bower_components",
"output"
],
"repository": {
"type": "git",
"url": "git://github.com/purescript-node/purescript-node-http.git"
"repository": {
"type": "git",
"url": "git://github.com/purescript-node/purescript-node-http.git"
},
"devDependencies": {
"purescript-console": "^0.1.0"
},
"dependencies": {
"purescript-maps": "^0.5.0",
"purescript-node-streams": "^0.1.1",
"purescript-options": "~0.5.1",
"purescript-unsafe-coerce": "^0.1.0"
}
}
136 changes: 136 additions & 0 deletions docs/Node/HTTP/Client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
## Module Node.HTTP.Client

This module defines low-level bindings to the Node HTTP client.

#### `Request`

``` purescript
data Request :: *
```

A HTTP request object

#### `Response`

``` purescript
data Response :: *
```

A HTTP response object

#### `RequestHeaders`

``` purescript
newtype RequestHeaders
```

A HTTP request object

##### Instances
``` purescript
instance requestHeadersIsOption :: IsOption RequestHeaders
```

#### `RequestOptions`

``` purescript
data RequestOptions
```

The type of HTTP request options

#### `protocol`

``` purescript
protocol :: Option RequestOptions String
```

The protocol to use

#### `hostname`

``` purescript
hostname :: Option RequestOptions String
```

Domain name or IP

#### `port`

``` purescript
port :: Option RequestOptions Int
```

Port of remote server

#### `method`

``` purescript
method :: Option RequestOptions String
```

The HTTP request method: GET, POST, etc.

#### `path`

``` purescript
path :: Option RequestOptions String
```

The request path, including query string if appropriate.

#### `headers`

``` purescript
headers :: Option RequestOptions String
```

#### `auth`

``` purescript
auth :: Option RequestOptions String
```

Basic authentication

#### `request`

``` purescript
request :: forall eff. Options RequestOptions -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request
```

Make a HTTP request using the specified options and response callback.

#### `requestAsStream`

``` purescript
requestAsStream :: forall eff r a. Request -> Writable r (http :: HTTP | eff) a
```

Create a writable stream from a request object.

#### `responseAsStream`

``` purescript
responseAsStream :: forall eff w a. Response -> Readable w (http :: HTTP | eff) a
```

Create a readable stream from a response object.

#### `httpVersion`

``` purescript
httpVersion :: Response -> String
```

Get the request HTTP version

#### `responseHeaders`

``` purescript
responseHeaders :: Response -> StrMap String
```

Get the response headers as a hash


15 changes: 15 additions & 0 deletions src/Node/HTTP/Client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";

// module Node.HTTP.Client

var http = require('http');

exports.requestImpl = function(opts) {
return function(k) {
return function() {
return http.request(opts, function(res) {
k(res)();
});
};
};
};
98 changes: 98 additions & 0 deletions src/Node/HTTP/Client.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
-- | This module defines low-level bindings to the Node HTTP client.

module Node.HTTP.Client
( Request()
, Response()
, RequestHeaders()
, RequestOptions()
, protocol
, hostname
, port
, method
, path
, headers
, auth
, request
, requestAsStream
, responseAsStream
, httpVersion
, responseHeaders
) where

import Prelude

import Data.Foreign
import Data.Options
import Data.StrMap (StrMap())

import Node.HTTP (HTTP())
import Node.Stream

import Control.Monad.Eff

import Unsafe.Coerce (unsafeCoerce)

-- | A HTTP request object
foreign import data Request :: *

-- | A HTTP response object
foreign import data Response :: *

-- | A HTTP request object
newtype RequestHeaders = RequestHeaders (StrMap String)

instance requestHeadersIsOption :: IsOption RequestHeaders where
assoc k v = assoc (optionFn k) (unsafeCoerce v :: {})

-- | The type of HTTP request options
data RequestOptions

-- | The protocol to use
protocol :: Option RequestOptions String
protocol = opt "protocol"

-- | Domain name or IP
hostname :: Option RequestOptions String
hostname = opt "hostname"

-- | Port of remote server
port :: Option RequestOptions Int
port = opt "port"

-- | The HTTP request method: GET, POST, etc.
method :: Option RequestOptions String
method = opt "method"

-- | The request path, including query string if appropriate.
path :: Option RequestOptions String
path = opt "path"

headers :: Option RequestOptions String
headers = opt "headers"

-- | Basic authentication
auth :: Option RequestOptions String
auth = opt "auth"

-- | Make a HTTP request using the specified options and response callback.
foreign import requestImpl :: forall eff. Foreign -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request

-- | Make a HTTP request using the specified options and response callback.
request :: forall eff. Options RequestOptions -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request
request = requestImpl <<< options

-- | Create a writable stream from a request object.
requestAsStream :: forall eff r a. Request -> Writable r (http :: HTTP | eff) a
requestAsStream = unsafeCoerce

-- | Create a readable stream from a response object.
responseAsStream :: forall eff w a. Response -> Readable w (http :: HTTP | eff) a
responseAsStream = unsafeCoerce

-- | Get the request HTTP version
httpVersion :: Response -> String
httpVersion = _.httpVersion <<< unsafeCoerce

-- | Get the response headers as a hash
responseHeaders :: Response -> StrMap String
responseHeaders = _.headers <<< unsafeCoerce
5 changes: 5 additions & 0 deletions test/Main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";

// module Test.Main

exports.stdout = process.stdout;
23 changes: 18 additions & 5 deletions test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,27 @@ module Test.Main where

import Prelude

import Data.Foldable (foldMap)
import Data.Options

import Control.Monad.Eff.Console

import Node.HTTP
import qualified Node.HTTP.Client as Client
import Node.Stream
import Node.Encoding

foreign import stdout :: forall eff r a. Writable r eff a

main = do
server <- createServer respond
listen server 8080 do
listen server 8080 $ void do
log "Listening on port 8080."
req <- Client.request (Client.hostname := "localhost" <> Client.port := 8080) \response -> void do
log "Response from GET /:"
let responseStream = Client.responseAsStream response
pipe responseStream stdout
end (Client.requestAsStream req) (return unit)
where
respond req res = do
setStatusCode res 200
Expand All @@ -20,10 +31,12 @@ main = do
log (requestMethod req <> " " <> requestURL req)
case requestMethod req of
"GET" -> do
let html = "<form method='POST' action='/'>"
<> " <input name='text' type='text'>"
<> " <input type='submit'>"
<> "</form>"
let html = foldMap (<> "\n")
[ "<form method='POST' action='/'>"
, " <input name='text' type='text'>"
, " <input type='submit'>"
, "</form>"
]
setHeader res "Content-Type" "text/html"
writeString outputStream UTF8 html(return unit)
end outputStream (return unit)
Expand Down

0 comments on commit 2fb1e83

Please sign in to comment.