Skip to content

Commit 37ae6c9

Browse files
Nicholas Scheelgaryb
authored andcommitted
Updates for PureScript 0.11 (#98)
* Update for PureScript 0.11 and API changes Use Data.Time.Duration.Milliseconds type in RetryPolicy, to go with Control.Monad.Aff.delay. Recreate the removed Data.Foreign.parseJSON locally. Update constraint syntax and kinds. * Update dependencies * Use Argonaut's jsonParser to implement parseJSON Removes the need for a foreign import. * Update test script syntax for PureScript 0.11 * v4.0.0 * Changes in response to #96 * Restore original formatting of imports * Bump versions in package.json
1 parent 071ca67 commit 37ae6c9

File tree

5 files changed

+60
-54
lines changed

5 files changed

+60
-54
lines changed

bower.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@
2323
"package.json"
2424
],
2525
"dependencies": {
26-
"purescript-aff": "^2.0.1",
27-
"purescript-argonaut-core": "^2.0.1",
28-
"purescript-arraybuffer-types": "^0.2.0",
29-
"purescript-dom": "^3.1.0",
30-
"purescript-foreign": "^3.0.0",
31-
"purescript-form-urlencoded": "^2.0.0",
32-
"purescript-http-methods": "^2.0.0",
33-
"purescript-integers": "^2.0.0",
26+
"purescript-aff": "^3.0.0",
27+
"purescript-argonaut-core": "^3.0.0",
28+
"purescript-arraybuffer-types": "^1.0.0",
29+
"purescript-dom": "^4.0.0",
30+
"purescript-foreign": "^4.0.0",
31+
"purescript-form-urlencoded": "^3.0.0",
32+
"purescript-http-methods": "^3.0.0",
33+
"purescript-integers": "^3.0.0",
3434
"purescript-math": "^2.0.0",
35-
"purescript-media-types": "^2.0.0",
36-
"purescript-nullable": "^2.0.0",
37-
"purescript-refs": "^2.0.0",
38-
"purescript-unsafe-coerce": "^2.0.0"
35+
"purescript-media-types": "^3.0.0",
36+
"purescript-nullable": "^3.0.0",
37+
"purescript-refs": "^3.0.0",
38+
"purescript-unsafe-coerce": "^3.0.0"
3939
},
4040
"devDependencies": {
41-
"purescript-console": "^2.0.0"
41+
"purescript-console": "^3.0.0"
4242
}
4343
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
"eslint": "^3.10.1",
1010
"body-parser": "^1.15.2",
1111
"express": "^4.14.0",
12-
"pulp": "^9.0.1",
13-
"purescript-psa": "^0.3.9",
14-
"purescript": "^0.10.2",
12+
"pulp": "^11.0.0",
13+
"purescript-psa": "^0.5.0",
14+
"purescript": "^0.11.0",
1515
"rimraf": "^2.5.4",
1616
"xhr2": "^0.1.3"
1717
}

src/Network/HTTP/Affjax.purs

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,28 @@ module Network.HTTP.Affjax
1919

2020
import Prelude hiding (max)
2121

22-
import Control.Monad.Aff (Aff, makeAff, makeAff', Canceler(..), attempt, later', forkAff, cancel)
22+
import Control.Monad.Aff (Aff, makeAff, makeAff', Canceler(..), attempt, delay, forkAff, cancel)
2323
import Control.Monad.Aff.AVar (AVAR, makeVar, takeVar, putVar)
24-
import Control.Monad.Eff (Eff)
24+
import Control.Monad.Eff (kind Effect, Eff)
2525
import Control.Monad.Eff.Class (liftEff)
2626
import Control.Monad.Eff.Exception (Error, error)
2727
import Control.Monad.Eff.Ref (REF, newRef, readRef, writeRef)
2828
import Control.Monad.Except (runExcept, throwError)
2929

30+
import Data.Argonaut.Parser (jsonParser)
3031
import Data.Array as Arr
3132
import Data.Either (Either(..), either)
3233
import Data.Foldable (any)
33-
import Data.Foreign (Foreign, F, parseJSON, readString)
34+
import Data.Foreign (F, Foreign, ForeignError(JSONError), fail, readString, toForeign)
3435
import Data.Function (on)
3536
import Data.Function.Uncurried (Fn5, runFn5, Fn4, runFn4)
3637
import Data.HTTP.Method (Method(..), CustomMethod)
3738
import Data.HTTP.Method as Method
38-
import Data.Int (toNumber, round)
39+
import Data.Int (toNumber)
3940
import Data.Maybe (Maybe(..))
4041
import Data.MediaType (MediaType)
4142
import Data.Nullable (Nullable, toNullable)
43+
import Data.Time.Duration (Milliseconds(..))
4244
import Data.Tuple (Tuple(..), fst, snd)
4345

4446
import Math (max, pow)
@@ -52,7 +54,7 @@ import Network.HTTP.ResponseHeader (ResponseHeader, responseHeader)
5254
import Network.HTTP.StatusCode (StatusCode(..))
5355

5456
-- | The effect type for AJAX requests made with Affjax.
55-
foreign import data AJAX :: !
57+
foreign import data AJAX :: Effect
5658

5759
-- | The type for Affjax requests.
5860
type Affjax e a = Aff (ajax :: AJAX | e) (AffjaxResponse a)
@@ -89,81 +91,81 @@ type AffjaxResponse a =
8991
type URL = String
9092

9193
-- | Makes an `Affjax` request.
92-
affjax :: forall e a b. (Requestable a, Respondable b) => AffjaxRequest a -> Affjax e b
94+
affjax :: forall e a b. Requestable a => Respondable b => AffjaxRequest a -> Affjax e b
9395
affjax = makeAff' <<< affjax'
9496

9597
-- | Makes a `GET` request to the specified URL.
96-
get :: forall e a. (Respondable a) => URL -> Affjax e a
98+
get :: forall e a. Respondable a => URL -> Affjax e a
9799
get u = affjax $ defaultRequest { url = u }
98100

99101
-- | Makes a `POST` request to the specified URL, sending data.
100-
post :: forall e a b. (Requestable a, Respondable b) => URL -> a -> Affjax e b
102+
post :: forall e a b. Requestable a => Respondable b => URL -> a -> Affjax e b
101103
post u c = affjax $ defaultRequest { method = Left POST, url = u, content = Just c }
102104

103105
-- | Makes a `POST` request to the specified URL with the option to send data.
104-
post' :: forall e a b. (Requestable a, Respondable b) => URL -> Maybe a -> Affjax e b
106+
post' :: forall e a b. Requestable a => Respondable b => URL -> Maybe a -> Affjax e b
105107
post' u c = affjax $ defaultRequest { method = Left POST, url = u, content = c }
106108

107109
-- | Makes a `POST` request to the specified URL, sending data and ignoring the
108110
-- | response.
109-
post_ :: forall e a. (Requestable a) => URL -> a -> Affjax e Unit
111+
post_ :: forall e a. Requestable a => URL -> a -> Affjax e Unit
110112
post_ = post
111113

112114
-- | Makes a `POST` request to the specified URL with the option to send data,
113115
-- | and ignores the response.
114-
post_' :: forall e a. (Requestable a) => URL -> Maybe a -> Affjax e Unit
116+
post_' :: forall e a. Requestable a => URL -> Maybe a -> Affjax e Unit
115117
post_' = post'
116118

117119
-- | Makes a `PUT` request to the specified URL, sending data.
118-
put :: forall e a b. (Requestable a, Respondable b) => URL -> a -> Affjax e b
120+
put :: forall e a b. Requestable a => Respondable b => URL -> a -> Affjax e b
119121
put u c = affjax $ defaultRequest { method = Left PUT, url = u, content = Just c }
120122

121123
-- | Makes a `PUT` request to the specified URL with the option to send data.
122-
put' :: forall e a b. (Requestable a, Respondable b) => URL -> Maybe a -> Affjax e b
124+
put' :: forall e a b. Requestable a => Respondable b => URL -> Maybe a -> Affjax e b
123125
put' u c = affjax $ defaultRequest { method = Left PUT, url = u, content = c }
124126

125127
-- | Makes a `PUT` request to the specified URL, sending data and ignoring the
126128
-- | response.
127-
put_ :: forall e a. (Requestable a) => URL -> a -> Affjax e Unit
129+
put_ :: forall e a. Requestable a => URL -> a -> Affjax e Unit
128130
put_ = put
129131

130132
-- | Makes a `PUT` request to the specified URL with the option to send data,
131133
-- | and ignores the response.
132-
put_' :: forall e a. (Requestable a) => URL -> Maybe a -> Affjax e Unit
134+
put_' :: forall e a. Requestable a => URL -> Maybe a -> Affjax e Unit
133135
put_' = put'
134136

135137
-- | Makes a `DELETE` request to the specified URL.
136-
delete :: forall e a. (Respondable a) => URL -> Affjax e a
138+
delete :: forall e a. Respondable a => URL -> Affjax e a
137139
delete u = affjax $ defaultRequest { method = Left DELETE, url = u }
138140

139141
-- | Makes a `DELETE` request to the specified URL and ignores the response.
140142
delete_ :: forall e. URL -> Affjax e Unit
141143
delete_ = delete
142144

143145
-- | Makes a `PATCH` request to the specified URL, sending data.
144-
patch :: forall e a b. (Requestable a, Respondable b) => URL -> a -> Affjax e b
146+
patch :: forall e a b. Requestable a => Respondable b => URL -> a -> Affjax e b
145147
patch u c = affjax $ defaultRequest { method = Left PATCH, url = u, content = Just c }
146148

147149
-- | Makes a `PATCH` request to the specified URL with the option to send data.
148-
patch' :: forall e a b. (Requestable a, Respondable b) => URL -> Maybe a -> Affjax e b
150+
patch' :: forall e a b. Requestable a => Respondable b => URL -> Maybe a -> Affjax e b
149151
patch' u c = affjax $ defaultRequest { method = Left PATCH, url = u, content = c }
150152

151153
-- | Makes a `PATCH` request to the specified URL, sending data and ignoring the
152154
-- | response.
153-
patch_ :: forall e a. (Requestable a) => URL -> a -> Affjax e Unit
155+
patch_ :: forall e a. Requestable a => URL -> a -> Affjax e Unit
154156
patch_ = patch
155157

156158
-- | Makes a `PATCH` request to the specified URL with the option to send data,
157159
-- | and ignores the response.
158-
patch_' :: forall e a. (Requestable a) => URL -> Maybe a -> Affjax e Unit
160+
patch_' :: forall e a. Requestable a => URL -> Maybe a -> Affjax e Unit
159161
patch_' = patch'
160162

161163
-- | A sequence of retry delays, in milliseconds.
162-
type RetryDelayCurve = Int -> Int
164+
type RetryDelayCurve = Int -> Milliseconds
163165

164166
-- | Expresses a policy for retrying Affjax requests with backoff.
165167
type RetryPolicy =
166-
{ timeout :: Maybe Int -- ^ the timeout in milliseconds, optional
168+
{ timeout :: Maybe Milliseconds -- ^ the timeout in milliseconds, optional
167169
, delayCurve :: RetryDelayCurve
168170
, shouldRetryWithStatusCode :: StatusCode -> Boolean -- ^ whether a non-200 status code should trigger a retry
169171
}
@@ -172,7 +174,7 @@ type RetryPolicy =
172174
defaultRetryPolicy :: RetryPolicy
173175
defaultRetryPolicy =
174176
{ timeout : Nothing
175-
, delayCurve : \n -> round $ max (30.0 * 1000.0) $ 100.0 * (pow 2.0 $ toNumber (n - 1))
177+
, delayCurve : \n -> Milliseconds $ max (30.0 * 1000.0) $ 100.0 * (pow 2.0 $ toNumber (n - 1))
176178
, shouldRetryWithStatusCode : const false
177179
}
178180

@@ -182,7 +184,7 @@ type RetryState e a = Either (Either e a) a
182184
-- | Retry a request using a `RetryPolicy`. After the timeout, the last received response is returned; if it was not possible to communicate with the server due to an error, then this is bubbled up.
183185
retry
184186
:: forall e a b
185-
. (Requestable a)
187+
. Requestable a
186188
=> RetryPolicy
187189
-> (AffjaxRequest a -> Affjax (avar :: AVAR, ref :: REF | e) b)
188190
-> (AffjaxRequest a -> Affjax (avar :: AVAR, ref :: REF | e) b)
@@ -196,7 +198,8 @@ retry policy run req = do
196198
respVar <- makeVar
197199
loopHandle <- forkAff $ loop 1 >>= putVar respVar <<< Just
198200
timeoutHandle <-
199-
forkAff <<< later' timeout $ do
201+
forkAff $ do
202+
delay timeout
200203
putVar respVar Nothing
201204
loopHandle `cancel` error "Cancel"
202205
result <- takeVar respVar
@@ -226,13 +229,15 @@ retry policy run req = do
226229
case result of
227230
Left err -> do
228231
liftEff $ writeRef failureRef $ Just err
229-
later' (policy.delayCurve n) $ go failureRef (n + 1)
232+
delay (policy.delayCurve n)
233+
go failureRef (n + 1)
230234
Right resp -> pure resp
231235

232236
-- | Run a request directly without using `Aff`.
233237
affjax'
234238
:: forall e a b
235-
. (Requestable a, Respondable b)
239+
. Requestable a
240+
=> Respondable b
236241
=> AffjaxRequest a
237242
-> (Error -> Eff (ajax :: AJAX | e) Unit)
238243
-> (AffjaxResponse b -> Eff (ajax :: AJAX | e) Unit)
@@ -277,6 +282,9 @@ affjax' req eb cb =
277282
Left err -> eb $ error (show err)
278283
Right res' -> cb res'
279284

285+
parseJSON :: String -> F Foreign
286+
parseJSON = either (fail <<< JSONError) (pure <<< toForeign) <<< jsonParser
287+
280288
fromResponse' :: ResponseContent -> F b
281289
fromResponse' = case snd responseSettings of
282290
JSONResponse -> fromResponse <=< parseJSON <=< readString

src/Network/HTTP/Affjax/Request.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Unsafe.Coerce as U
2222

2323
-- | Type representing all content types that be sent via XHR (ArrayBufferView,
2424
-- | Blob, Document, String, FormData).
25-
foreign import data RequestContent :: *
25+
foreign import data RequestContent :: Type
2626

2727
-- | A class for types that can be converted to values that can be sent with
2828
-- | XHR requests. An optional mime-type can be specified for a default

test/Main.purs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
module Test.Main where
22

33
import Prelude
4-
4+
import Control.Monad.Aff.Console as A
5+
import Network.HTTP.Affjax as AX
56
import Control.Monad.Aff (Aff, cancel, forkAff, attempt, runAff, makeAff)
67
import Control.Monad.Aff.AVar (AVAR)
7-
import Control.Monad.Aff.Console as A
88
import Control.Monad.Eff (Eff)
99
import Control.Monad.Eff.Class (liftEff)
1010
import Control.Monad.Eff.Console (CONSOLE, log, logShow)
1111
import Control.Monad.Eff.Exception (EXCEPTION, error, throwException)
1212
import Control.Monad.Eff.Ref (REF)
13-
1413
import Data.Either (Either(..))
1514
import Data.Foreign (Foreign, unsafeFromForeign)
1615
import Data.Maybe (Maybe(..))
17-
18-
import Network.HTTP.Affjax as AX
16+
import Data.Time.Duration (Milliseconds(..))
1917
import Network.HTTP.StatusCode (StatusCode(..))
2018

2119
foreign import logAny :: forall e a. a -> Eff (console :: CONSOLE | e) Unit
2220

2321
logAny' :: forall e a. a -> Assert e Unit
2422
logAny' = liftEff <<< logAny
2523

26-
type Assert e a = Aff (err :: EXCEPTION, console :: CONSOLE, ajax :: AX.AJAX | e) a
24+
type Assert e a = Aff (exception :: EXCEPTION, console :: CONSOLE, ajax :: AX.AJAX | e) a
2725

2826
assertFail :: forall e a. String -> Assert e a
2927
assertFail msg = makeAff \errback _ -> errback (error msg)
@@ -42,7 +40,7 @@ assertLeft x = case x of
4240
Right y -> logAny' y >>= \_ -> assertFail "Expected a Left value"
4341
Left y -> pure y
4442

45-
assertEq :: forall e a. (Eq a, Show a) => a -> a -> Assert e Unit
43+
assertEq :: forall e a. Eq a => Show a => a -> a -> Assert e Unit
4644
assertEq x y =
4745
when (x /= y) $ assertFail $ "Expected " <> show x <> ", got " <> show y
4846

@@ -53,7 +51,7 @@ typeIs = const (pure unit)
5351
type MainEffects e =
5452
( ref :: REF
5553
, avar :: AVAR
56-
, err :: EXCEPTION
54+
, exception :: EXCEPTION
5755
, console :: CONSOLE
5856
| e
5957
)
@@ -68,7 +66,7 @@ main = void $ runAff (\e -> logShow e >>= \_ -> throwException e) (const $ log "
6866
let mirror = prefix "/mirror"
6967
let doesNotExist = prefix "/does-not-exist"
7068
let notJson = prefix "/not-json"
71-
let retryPolicy = AX.defaultRetryPolicy { timeout = Just 500, shouldRetryWithStatusCode = \_ -> true }
69+
let retryPolicy = AX.defaultRetryPolicy { timeout = Just (Milliseconds 500.0), shouldRetryWithStatusCode = \_ -> true }
7270

7371
A.log "GET /does-not-exist: should be 404 Not found after retries"
7472
(attempt $ AX.retry retryPolicy AX.affjax $ AX.defaultRequest { url = doesNotExist }) >>= assertRight >>= \res -> do
@@ -86,7 +84,7 @@ main = void $ runAff (\e -> logShow e >>= \_ -> throwException e) (const $ log "
8684
assertEq notFound404 res.status
8785

8886
A.log "GET /not-json: invalid JSON with Foreign response should throw an error"
89-
assertLeft =<< attempt (AX.get doesNotExist :: AX.Affjax (MainEffects ()) Foreign)
87+
void $ assertLeft =<< attempt (AX.get doesNotExist :: AX.Affjax (MainEffects ()) Foreign)
9088

9189
A.log "GET /not-json: invalid JSON with String response should be ok"
9290
(attempt $ AX.get notJson) >>= assertRight >>= \res -> do

0 commit comments

Comments
 (0)