Skip to content

Commit 859fc22

Browse files
committed
Merge pull request #53 from garyb/headers
Include mime types in Requestable/Respondable for setting headers
2 parents 795dd67 + 9b66ff7 commit 859fc22

File tree

7 files changed

+114
-52
lines changed

7 files changed

+114
-52
lines changed

bower.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
],
2525
"dependencies": {
2626
"purescript-aff": "^0.13.0",
27+
"purescript-argonaut-core": "^0.2.0",
2728
"purescript-arraybuffer-types": "^0.2.0",
2829
"purescript-dom": "^0.2.0",
2930
"purescript-foreign": "^0.7.0",

docs/Network.HTTP.Affjax.Request.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ instance requestableRequestContent :: Requestable RequestContent
1818

1919
``` purescript
2020
class Requestable a where
21-
toRequest :: a -> RequestContent
21+
toRequest :: a -> Tuple (Maybe MimeType) RequestContent
2222
```
2323

2424
A class for types that can be converted to values that can be sent with
25-
XHR requests.
25+
XHR requests. An optional mime-type can be specified for a default
26+
`Content-Type` header.
2627

2728
##### Instances
2829
``` purescript
@@ -39,6 +40,7 @@ instance requestableFloat64Array :: Requestable (ArrayView Float64)
3940
instance requestableBlob :: Requestable Blob
4041
instance requestableDocument :: Requestable Document
4142
instance requestableString :: Requestable String
43+
instance requestableJson :: Requestable Json
4244
instance requestableFormData :: Requestable FormData
4345
instance requestableUnit :: Requestable Unit
4446
```

docs/Network.HTTP.Affjax.Response.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,26 @@ type ResponseContent = Foreign
3535
```
3636

3737
Type representing content types that be received from an XHR request
38-
(Blob, Document, JSON, String).
38+
(Blob, Document, JSON, String). An optional mime-type can be specified for
39+
a default `Accept` header.
3940

4041
#### `Respondable`
4142

4243
``` purescript
4344
class Respondable a where
44-
responseType :: ResponseType a
45+
responseType :: Tuple (Maybe MimeType) (ResponseType a)
4546
fromResponse :: ResponseContent -> F a
4647
```
4748

4849
##### Instances
4950
``` purescript
5051
instance responsableBlob :: Respondable Blob
5152
instance responsableDocument :: Respondable Document
52-
instance responsableJSON :: Respondable Foreign
53+
instance responsableForeign :: Respondable Foreign
5354
instance responsableString :: Respondable String
5455
instance responsableUnit :: Respondable Unit
56+
instance responsableArrayBuffer :: Respondable ArrayBuffer
57+
instance responsableJson :: Respondable Json
5558
```
5659

5760

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"gulp-jshint": "^1.11.2",
99
"gulp-plumber": "^1.0.0",
1010
"gulp-purescript": "^0.6.0",
11-
"purescript": "^0.7.4-rc.2",
11+
"purescript": "^0.7.5",
1212
"xhr2": "^0.1.3"
1313
}
1414
}

src/Network/HTTP/Affjax.purs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,34 @@ module Network.HTTP.Affjax
1717
) where
1818

1919
import Prelude
20-
import Control.Alt ((<|>))
21-
import Control.Bind ((<=<))
20+
2221
import Control.Monad.Aff (Aff(), makeAff, makeAff', Canceler(..), attempt, later', forkAff, cancel)
23-
import Control.Monad.Aff.Par (Par(..), runPar)
2422
import Control.Monad.Aff.AVar (AVAR(), makeVar, takeVar, putVar)
2523
import Control.Monad.Eff (Eff())
2624
import Control.Monad.Eff.Class (liftEff)
2725
import Control.Monad.Eff.Exception (Error(), error)
2826
import Control.Monad.Eff.Ref (REF(), newRef, readRef, writeRef)
2927
import Control.Monad.Error.Class (throwError)
28+
29+
import Data.Array as Arr
3030
import Data.Either (Either(..), either)
31-
import Data.Foreign (Foreign(), F(), parseJSON, readString)
32-
import Data.Function (Fn5(), runFn5, Fn4(), runFn4)
31+
import Data.Foreign (Foreign())
32+
import Data.Foldable (any)
33+
import Data.Function (Fn5(), runFn5, Fn4(), runFn4, on)
3334
import Data.Int (toNumber, round)
34-
import Data.Maybe (Maybe(..), maybe)
35+
import Data.Maybe (Maybe(..))
3536
import Data.Nullable (Nullable(), toNullable)
36-
import DOM.XHR.Types (XMLHttpRequest())
37+
import Data.Tuple (Tuple(..), fst, snd)
38+
3739
import Math (max, pow)
40+
41+
import DOM.XHR.Types (XMLHttpRequest())
42+
3843
import Network.HTTP.Affjax.Request
3944
import Network.HTTP.Affjax.Response
45+
import Network.HTTP.MimeType (MimeType())
4046
import Network.HTTP.Method (Method(..), methodToString)
41-
import Network.HTTP.RequestHeader (RequestHeader(), requestHeaderName, requestHeaderValue)
47+
import Network.HTTP.RequestHeader (RequestHeader(..), requestHeaderName, requestHeaderValue)
4248
import Network.HTTP.ResponseHeader (ResponseHeader(), responseHeader)
4349
import Network.HTTP.StatusCode (StatusCode(..))
4450

@@ -202,23 +208,40 @@ affjax' :: forall e a b. (Requestable a, Respondable b) =>
202208
affjax' req eb cb =
203209
runFn5 _ajax responseHeader req' cancelAjax eb cb'
204210
where
211+
205212
req' :: AjaxRequest
206213
req' = { method: methodToString req.method
207214
, url: req.url
208-
, headers: (\h -> { field: requestHeaderName h, value: requestHeaderValue h }) <$> req.headers
209-
, content: toNullable (toRequest <$> req.content)
210-
, responseType: responseTypeToString (responseType :: ResponseType b)
215+
, headers: (\h -> { field: requestHeaderName h, value: requestHeaderValue h }) <$> headers
216+
, content: toNullable (snd requestSettings)
217+
, responseType: responseTypeToString (snd responseSettings)
211218
, username: toNullable req.username
212219
, password: toNullable req.password
213220
}
221+
222+
requestSettings :: Tuple (Maybe MimeType) (Maybe RequestContent)
223+
requestSettings = case toRequest <$> req.content of
224+
Nothing -> Tuple Nothing Nothing
225+
Just (Tuple mime rt) -> Tuple mime (Just rt)
226+
227+
responseSettings :: Tuple (Maybe MimeType) (ResponseType b)
228+
responseSettings = responseType
229+
230+
headers :: Array RequestHeader
231+
headers =
232+
addHeader (ContentType <$> fst requestSettings) $
233+
addHeader (Accept <$> fst responseSettings)
234+
req.headers
235+
236+
addHeader :: Maybe RequestHeader -> Array RequestHeader -> Array RequestHeader
237+
addHeader h hs = case h of
238+
Just h | not $ any (on eq requestHeaderName h) hs -> hs `Arr.snoc` h
239+
_ -> hs
240+
214241
cb' :: AffjaxResponse ResponseContent -> Eff (ajax :: AJAX | e) Unit
215-
cb' res = case res { response = _ } <$> fromResponse' res.response of
242+
cb' res = case res { response = _ } <$> fromResponse res.response of
216243
Left err -> eb $ error (show err)
217244
Right res' -> cb res'
218-
fromResponse' :: ResponseContent -> F b
219-
fromResponse' = case (responseType :: ResponseType b) of
220-
JSONResponse -> fromResponse <=< parseJSON <=< readString
221-
_ -> fromResponse
222245

223246
type AjaxRequest =
224247
{ method :: String

src/Network/HTTP/Affjax/Request.purs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,78 @@ module Network.HTTP.Affjax.Request
44
) where
55

66
import Prelude
7+
8+
import Data.Argonaut.Core (Json())
9+
import Data.Maybe (Maybe(..))
10+
import Data.Tuple (Tuple(..))
11+
import qualified Data.ArrayBuffer.Types as A
12+
713
import DOM.File.Types (Blob())
814
import DOM.Node.Types (Document())
915
import DOM.XHR.Types (FormData())
16+
1017
import qualified Unsafe.Coerce as U
11-
import qualified Data.ArrayBuffer.Types as A
18+
19+
import Network.HTTP.MimeType (MimeType())
20+
import Network.HTTP.MimeType.Common (applicationJSON)
1221

1322
-- | Type representing all content types that be sent via XHR (ArrayBufferView,
1423
-- | Blob, Document, String, FormData).
1524
foreign import data RequestContent :: *
1625

1726
-- | A class for types that can be converted to values that can be sent with
18-
-- | XHR requests.
27+
-- | XHR requests. An optional mime-type can be specified for a default
28+
-- | `Content-Type` header.
1929
class Requestable a where
20-
toRequest :: a -> RequestContent
30+
toRequest :: a -> Tuple (Maybe MimeType) RequestContent
31+
32+
defaultToRequest :: forall a. a -> Tuple (Maybe MimeType) RequestContent
33+
defaultToRequest = Tuple Nothing <<< U.unsafeCoerce
2134

2235
instance requestableRequestContent :: Requestable RequestContent where
23-
toRequest = id
36+
toRequest = defaultToRequest
2437

2538
instance requestableInt8Array :: Requestable (A.ArrayView A.Int8) where
26-
toRequest = U.unsafeCoerce
39+
toRequest = defaultToRequest
2740

2841
instance requestableInt16Array :: Requestable (A.ArrayView A.Int16) where
29-
toRequest = U.unsafeCoerce
42+
toRequest = defaultToRequest
3043

3144
instance requestableInt32Array :: Requestable (A.ArrayView A.Int32) where
32-
toRequest = U.unsafeCoerce
45+
toRequest = defaultToRequest
3346

3447
instance requestableUint8Array :: Requestable (A.ArrayView A.Uint8) where
35-
toRequest = U.unsafeCoerce
48+
toRequest = defaultToRequest
3649

3750
instance requestableUint16Array :: Requestable (A.ArrayView A.Uint16) where
38-
toRequest = U.unsafeCoerce
51+
toRequest = defaultToRequest
3952

4053
instance requestableUint32Array :: Requestable (A.ArrayView A.Uint32) where
41-
toRequest = U.unsafeCoerce
54+
toRequest = defaultToRequest
4255

4356
instance requestableUint8ClampedArray :: Requestable (A.ArrayView A.Uint8Clamped) where
44-
toRequest = U.unsafeCoerce
57+
toRequest = defaultToRequest
4558

4659
instance requestableFloat32Array :: Requestable (A.ArrayView A.Float32) where
47-
toRequest = U.unsafeCoerce
60+
toRequest = defaultToRequest
4861

4962
instance requestableFloat64Array :: Requestable (A.ArrayView A.Float64) where
50-
toRequest = U.unsafeCoerce
63+
toRequest = defaultToRequest
5164

5265
instance requestableBlob :: Requestable Blob where
53-
toRequest = U.unsafeCoerce
66+
toRequest = defaultToRequest
5467

5568
instance requestableDocument :: Requestable Document where
56-
toRequest = U.unsafeCoerce
69+
toRequest = defaultToRequest
5770

5871
instance requestableString :: Requestable String where
59-
toRequest = U.unsafeCoerce
72+
toRequest = defaultToRequest
73+
74+
instance requestableJson :: Requestable Json where
75+
toRequest json = Tuple (Just applicationJSON) (U.unsafeCoerce (show json))
6076

6177
instance requestableFormData :: Requestable FormData where
62-
toRequest = U.unsafeCoerce
78+
toRequest = defaultToRequest
6379

6480
instance requestableUnit :: Requestable Unit where
65-
toRequest = U.unsafeCoerce
81+
toRequest = defaultToRequest

src/Network/HTTP/Affjax/Response.purs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,24 @@ module Network.HTTP.Affjax.Response
55
) where
66

77
import Prelude
8+
9+
import Control.Bind ((<=<))
10+
11+
import Data.Argonaut.Core (Json())
812
import Data.Either (Either(..))
9-
import Data.Foreign (Foreign(), F(), readString, unsafeReadTagged)
13+
import Data.Foreign (Foreign(), F(), parseJSON, readString, unsafeReadTagged)
14+
import Data.Maybe (Maybe(..))
15+
import Data.Tuple (Tuple(..))
16+
import qualified Data.ArrayBuffer.Types as A
17+
1018
import DOM.File.Types (Blob())
1119
import DOM.Node.Types (Document())
1220
import DOM.XHR.Types (FormData())
13-
import qualified Data.ArrayBuffer.Types as A
21+
22+
import Unsafe.Coerce (unsafeCoerce)
23+
24+
import Network.HTTP.MimeType (MimeType())
25+
import Network.HTTP.MimeType.Common (applicationJSON)
1426

1527
-- | Valid response types for an AJAX request. This is used to determine the
1628
-- | `ResponseContent` type for a request. The `a` type variable is a phantom
@@ -46,33 +58,38 @@ responseTypeToString JSONResponse = "text" -- IE doesn't support "json" response
4658
responseTypeToString StringResponse = "text"
4759

4860
-- | Type representing content types that be received from an XHR request
49-
-- | (Blob, Document, JSON, String).
61+
-- | (Blob, Document, JSON, String). An optional mime-type can be specified for
62+
-- | a default `Accept` header.
5063
type ResponseContent = Foreign
5164

5265
class Respondable a where
53-
responseType :: ResponseType a
66+
responseType :: Tuple (Maybe MimeType) (ResponseType a)
5467
fromResponse :: ResponseContent -> F a
5568

5669
instance responsableBlob :: Respondable Blob where
57-
responseType = BlobResponse
70+
responseType = Tuple Nothing BlobResponse
5871
fromResponse = unsafeReadTagged "Blob"
5972

6073
instance responsableDocument :: Respondable Document where
61-
responseType = DocumentResponse
74+
responseType = Tuple Nothing DocumentResponse
6275
fromResponse = unsafeReadTagged "Document"
6376

64-
instance responsableJSON :: Respondable Foreign where
65-
responseType = JSONResponse
66-
fromResponse = Right
77+
instance responsableForeign :: Respondable Foreign where
78+
responseType = Tuple Nothing JSONResponse
79+
fromResponse = parseJSON <=< readString
6780

6881
instance responsableString :: Respondable String where
69-
responseType = StringResponse
82+
responseType = Tuple Nothing StringResponse
7083
fromResponse = readString
7184

7285
instance responsableUnit :: Respondable Unit where
73-
responseType = StringResponse
86+
responseType = Tuple Nothing StringResponse
7487
fromResponse = const (Right unit)
7588

7689
instance responsableArrayBuffer :: Respondable A.ArrayBuffer where
77-
responseType = ArrayBufferResponse
90+
responseType = Tuple Nothing ArrayBufferResponse
7891
fromResponse = unsafeReadTagged "ArrayBuffer"
92+
93+
instance responsableJson :: Respondable Json where
94+
responseType = Tuple (Just applicationJSON) JSONResponse
95+
fromResponse = Right <<< unsafeCoerce

0 commit comments

Comments
 (0)