11module Network.HTTP.Affjax
2- ( AJAX
3- , Affjax
2+ ( Affjax
43 , AffjaxRequest , defaultRequest
5- , AffjaxResponse
4+ , AffjaxResponseT
65 , URL
76 , affjax
87 , get
@@ -19,44 +18,39 @@ module Network.HTTP.Affjax
1918
2019import Prelude
2120
22- import Control.Monad.Aff (Aff , try , delay )
23- import Control.Monad.Aff.Compat as AC
24- import Control.Monad.Eff (kind Effect )
25- import Control.Monad.Eff.Class (liftEff )
26- import Control.Monad.Eff.Exception (Error , error )
27- import Control.Monad.Eff.Ref (REF , newRef , readRef , writeRef )
2821import Control.Monad.Except (runExcept , throwError )
2922import Control.Parallel (parOneOf )
23+ import Data.Argonaut.Core (Json )
3024import Data.Argonaut.Core as J
3125import Data.Argonaut.Parser (jsonParser )
3226import Data.Array as Arr
3327import Data.Either (Either (..), either )
3428import Data.Foldable (any )
35- import Data.Foreign (F , Foreign , ForeignError (JSONError), fail , readString , toForeign )
3629import Data.FormURLEncoded as FormURLEncoded
3730import Data.Function (on )
3831import Data.Function.Uncurried (Fn2 , runFn2 )
3932import Data.HTTP.Method (Method (..), CustomMethod )
4033import Data.HTTP.Method as Method
4134import Data.Int (toNumber )
4235import Data.Maybe (Maybe (..))
43- import Data.MediaType (MediaType )
4436import Data.Nullable (Nullable , toNullable )
4537import Data.Time.Duration (Milliseconds (..))
46- import Data.Tuple (Tuple , fst , snd )
38+ import Effect.Aff (Aff , try , delay )
39+ import Effect.Aff.Compat as AC
40+ import Effect.Class (liftEffect )
41+ import Effect.Exception (Error , error )
42+ import Effect.Ref as Ref
43+ import Foreign (F , Foreign , ForeignError (..), fail , unsafeReadTagged , unsafeToForeign )
4744import Math as Math
48- import Network.HTTP.Affjax.Request (RequestContent (..)) as Exports
4945import Network.HTTP.Affjax.Request (RequestContent (..), defaultMediaType )
50- import Network.HTTP.Affjax.Response (class Respondable , ResponseContent , ResponseType (..), fromResponse , responseType , responseTypeToString )
46+ import Network.HTTP.Affjax.Request (RequestContent (..)) as Exports
47+ import Network.HTTP.Affjax.Response (AffjaxResponse (..), responseTypeToMediaType , responseTypeToString )
5148import Network.HTTP.RequestHeader (RequestHeader (..), requestHeaderName , requestHeaderValue )
5249import Network.HTTP.ResponseHeader (ResponseHeader , responseHeader )
5350import Network.HTTP.StatusCode (StatusCode (..))
5451
55- -- | The effect type for AJAX requests made with Affjax.
56- foreign import data AJAX :: Effect
57-
5852-- | The result type for Affjax requests.
59- type Affjax eff a = Aff (ajax :: AJAX | eff ) ( AffjaxResponse a )
53+ type Affjax a = Aff (AffjaxResponseT a )
6054
6155type AffjaxRequest =
6256 { method :: Either Method CustomMethod
@@ -80,7 +74,7 @@ defaultRequest =
8074 }
8175
8276-- | The type of records that will be received as an Affjax response.
83- type AffjaxResponse a =
77+ type AffjaxResponseT a =
8478 { status :: StatusCode
8579 , headers :: Array ResponseHeader
8680 , response :: a
@@ -90,70 +84,70 @@ type AffjaxResponse a =
9084type URL = String
9185
9286-- | Makes a `GET` request to the specified URL.
93- get :: forall e a . Respondable a = > URL -> Affjax e a
94- get u = affjax $ defaultRequest { url = u }
87+ get :: forall a . AffjaxResponse a - > URL -> Affjax a
88+ get rt u = affjax rt $ defaultRequest { url = u }
9589
9690-- | Makes a `POST` request to the specified URL, sending data.
97- post :: forall e a b . Respondable b = > URL -> RequestContent -> Affjax e b
98- post u c = affjax $ defaultRequest { method = Left POST , url = u, content = Just c }
91+ post :: forall a . AffjaxResponse a - > URL -> RequestContent -> Affjax a
92+ post rt u c = affjax rt $ defaultRequest { method = Left POST , url = u, content = Just c }
9993
10094-- | Makes a `POST` request to the specified URL with the option to send data.
101- post' :: forall e a b . Respondable b = > URL -> Maybe RequestContent -> Affjax e b
102- post' u c = affjax $ defaultRequest { method = Left POST , url = u, content = c }
95+ post' :: forall a . AffjaxResponse a - > URL -> Maybe RequestContent -> Affjax a
96+ post' rt u c = affjax rt $ defaultRequest { method = Left POST , url = u, content = c }
10397
10498-- | Makes a `POST` request to the specified URL, sending data and ignoring the
10599-- | response.
106- post_ :: forall e a . URL -> RequestContent -> Affjax e Unit
107- post_ = post
100+ post_ :: URL -> RequestContent -> Affjax Unit
101+ post_ = post ( IgnoredResponse identity)
108102
109103-- | Makes a `POST` request to the specified URL with the option to send data,
110104-- | and ignores the response.
111- post_' :: forall e a . URL -> Maybe RequestContent -> Affjax e Unit
112- post_' = post'
105+ post_' :: URL -> Maybe RequestContent -> Affjax Unit
106+ post_' = post' ( IgnoredResponse identity)
113107
114108-- | Makes a `PUT` request to the specified URL, sending data.
115- put :: forall e a b . Respondable b = > URL -> RequestContent -> Affjax e b
116- put u c = affjax $ defaultRequest { method = Left PUT , url = u, content = Just c }
109+ put :: forall a . AffjaxResponse a - > URL -> RequestContent -> Affjax a
110+ put rt u c = affjax rt $ defaultRequest { method = Left PUT , url = u, content = Just c }
117111
118112-- | Makes a `PUT` request to the specified URL with the option to send data.
119- put' :: forall e a b . Respondable b = > URL -> Maybe RequestContent -> Affjax e b
120- put' u c = affjax $ defaultRequest { method = Left PUT , url = u, content = c }
113+ put' :: forall a . AffjaxResponse a - > URL -> Maybe RequestContent -> Affjax a
114+ put' rt u c = affjax rt $ defaultRequest { method = Left PUT , url = u, content = c }
121115
122116-- | Makes a `PUT` request to the specified URL, sending data and ignoring the
123117-- | response.
124- put_ :: forall e a . URL -> RequestContent -> Affjax e Unit
125- put_ = put
118+ put_ :: URL -> RequestContent -> Affjax Unit
119+ put_ = put ( IgnoredResponse identity)
126120
127121-- | Makes a `PUT` request to the specified URL with the option to send data,
128122-- | and ignores the response.
129- put_' :: forall e a . URL -> Maybe RequestContent -> Affjax e Unit
130- put_' = put'
123+ put_' :: URL -> Maybe RequestContent -> Affjax Unit
124+ put_' = put' ( IgnoredResponse identity)
131125
132126-- | Makes a `DELETE` request to the specified URL.
133- delete :: forall e a . Respondable a = > URL -> Affjax e a
134- delete u = affjax $ defaultRequest { method = Left DELETE , url = u }
127+ delete :: forall a . AffjaxResponse a - > URL -> Affjax a
128+ delete rt u = affjax rt $ defaultRequest { method = Left DELETE , url = u }
135129
136130-- | Makes a `DELETE` request to the specified URL and ignores the response.
137- delete_ :: forall e . URL -> Affjax e Unit
138- delete_ = delete
131+ delete_ :: URL -> Affjax Unit
132+ delete_ = delete ( IgnoredResponse identity)
139133
140134-- | Makes a `PATCH` request to the specified URL, sending data.
141- patch :: forall e a b . Respondable b = > URL -> RequestContent -> Affjax e b
142- patch u c = affjax $ defaultRequest { method = Left PATCH , url = u, content = Just c }
135+ patch :: forall a . AffjaxResponse a - > URL -> RequestContent -> Affjax a
136+ patch rt u c = affjax rt $ defaultRequest { method = Left PATCH , url = u, content = Just c }
143137
144138-- | Makes a `PATCH` request to the specified URL with the option to send data.
145- patch' :: forall e a b . Respondable b = > URL -> Maybe RequestContent -> Affjax e b
146- patch' u c = affjax $ defaultRequest { method = Left PATCH , url = u, content = c }
139+ patch' :: forall a . AffjaxResponse a - > URL -> Maybe RequestContent -> Affjax a
140+ patch' rt u c = affjax rt $ defaultRequest { method = Left PATCH , url = u, content = c }
147141
148142-- | Makes a `PATCH` request to the specified URL, sending data and ignoring the
149143-- | response.
150- patch_ :: forall e a . URL -> RequestContent -> Affjax e Unit
151- patch_ = patch
144+ patch_ :: URL -> RequestContent -> Affjax Unit
145+ patch_ = patch ( IgnoredResponse identity)
152146
153147-- | Makes a `PATCH` request to the specified URL with the option to send data,
154148-- | and ignores the response.
155- patch_' :: forall e a . URL -> Maybe RequestContent -> Affjax e Unit
156- patch_' = patch'
149+ patch_' :: URL -> Maybe RequestContent -> Affjax Unit
150+ patch_' = patch' ( IgnoredResponse identity)
157151
158152-- | A sequence of retry delays, in milliseconds.
159153type RetryDelayCurve = Int -> Milliseconds
@@ -177,31 +171,26 @@ defaultRetryPolicy =
177171type RetryState e a = Either (Either e a ) a
178172
179173-- | 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.
180- retry
181- :: forall e a b
182- . RetryPolicy
183- -> (AffjaxRequest -> Affjax (ref :: REF | e ) b )
184- -> AffjaxRequest
185- -> Affjax (ref :: REF | e ) b
174+ retry :: forall a . RetryPolicy -> (AffjaxRequest -> Affjax a ) -> AffjaxRequest -> Affjax a
186175retry policy run req = do
187176 -- failureRef is either an exception or a failed request
188- failureRef <- liftEff $ newRef Nothing
177+ failureRef <- liftEffect $ Ref .new Nothing
189178 let loop = go failureRef
190179 case policy.timeout of
191180 Nothing -> loop 1
192181 Just timeout -> do
193182 result <- parOneOf [ Just <$> loop 1 , Nothing <$ delay timeout ]
194183 case result of
195184 Nothing -> do
196- failure <- liftEff $ readRef failureRef
185+ failure <- liftEffect $ Ref .read failureRef
197186 case failure of
198187 Nothing -> throwError $ error " Timeout"
199188 Just failure' -> either throwError pure failure'
200189 Just resp -> pure resp
201190 where
202191 retryState
203- :: Either Error (AffjaxResponse b )
204- -> RetryState Error (AffjaxResponse b )
192+ :: Either Error (AffjaxResponseT a )
193+ -> RetryState Error (AffjaxResponseT a )
205194 retryState (Left exn) = Left $ Left exn
206195 retryState (Right resp) =
207196 case resp.status of
@@ -216,77 +205,66 @@ retry policy run req = do
216205 result <- retryState <$> try (run req)
217206 case result of
218207 Left err -> do
219- liftEff $ writeRef failureRef $ Just err
208+ liftEffect $ Ref .write ( Just err) failureRef
220209 delay (policy.delayCurve n)
221210 go failureRef (n + 1 )
222211 Right resp -> pure resp
223212
224213-- | Makes an `Affjax` request.
225- affjax
226- :: forall e a b
227- . Respondable b
228- => AffjaxRequest
229- -> Affjax e b
230- affjax req = do
231- res <- AC .fromEffFnAff $ runFn2 _ajax responseHeader req'
232- case res { response = _ } <$> runExcept (fromResponse' res.response) of
214+ affjax :: forall a . AffjaxResponse a -> AffjaxRequest -> Affjax a
215+ affjax rt req = do
216+ res <- AC .fromEffectFnAff $ runFn2 _ajax responseHeader req'
217+ case runExcept (fromResponse' res.response) of
233218 Left err -> throwError $ error (show err)
234- Right res' -> pure res'
219+ Right res' -> pure ( res { response = res' })
235220 where
236221
237- req' :: AjaxRequest
222+ req' :: AjaxRequest a
238223 req' =
239224 { method: Method .print req.method
240225 , url: req.url
241226 , headers: (\h -> { field: requestHeaderName h, value: requestHeaderValue h }) <$> headers req.content
242227 , content: toNullable (extractContent <$> req.content)
243- , responseType: responseTypeToString (snd responseSettings)
228+ , responseType: responseTypeToString rt
244229 , username: toNullable req.username
245230 , password: toNullable req.password
246231 , withCredentials: req.withCredentials
247232 }
248233
249234 extractContent :: RequestContent -> Foreign
250235 extractContent = case _ of
251- ArrayViewInt8Request x → toForeign x
252- ArrayViewInt16Request x → toForeign x
253- ArrayViewInt32Request x → toForeign x
254- ArrayViewUint8Request x → toForeign x
255- ArrayViewUint16Request x → toForeign x
256- ArrayViewUint32Request x → toForeign x
257- ArrayViewUint8ClampedRequest x → toForeign x
258- ArrayViewFloat32Request x → toForeign x
259- ArrayViewFloat64Request x → toForeign x
260- BlobRequest x → toForeign x
261- DocumentRequest x → toForeign x
262- StringRequest x → toForeign x
263- FormDataRequest x → toForeign x
264- FormURLEncodedRequest x → toForeign (FormURLEncoded .encode x)
265- JsonRequest x → toForeign (J .stringify x)
266-
267- responseSettings :: Tuple (Maybe MediaType ) (ResponseType b )
268- responseSettings = responseType
236+ ArrayView f → f unsafeToForeign
237+ BlobRequest x → unsafeToForeign x
238+ DocumentRequest x → unsafeToForeign x
239+ StringRequest x → unsafeToForeign x
240+ FormDataRequest x → unsafeToForeign x
241+ FormURLEncodedRequest x → unsafeToForeign (FormURLEncoded .encode x)
242+ JsonRequest x → unsafeToForeign (J .stringify x)
269243
270244 headers :: Maybe RequestContent -> Array RequestHeader
271245 headers reqContent =
272246 addHeader (ContentType <$> (defaultMediaType =<< reqContent)) $
273- addHeader (Accept <$> fst responseSettings )
247+ addHeader (Accept <$> responseTypeToMediaType rt )
274248 req.headers
275249
276250 addHeader :: Maybe RequestHeader -> Array RequestHeader -> Array RequestHeader
277251 addHeader mh hs = case mh of
278252 Just h | not $ any (on eq requestHeaderName h) hs -> hs `Arr.snoc` h
279253 _ -> hs
280254
281- parseJSON :: String -> F Foreign
282- parseJSON = either (fail <<< JSONError ) ( pure <<< toForeign) <<< jsonParser
255+ parseJSON :: String -> F Json
256+ parseJSON = either (fail <<< ForeignError ) pure <<< jsonParser
283257
284- fromResponse' :: ResponseContent -> F b
285- fromResponse' = case snd responseSettings of
286- JSONResponse -> fromResponse <=< parseJSON <=< readString
287- _ -> fromResponse
258+ fromResponse' :: Foreign -> F a
259+ fromResponse' rc = case rt of
260+ ArrayBufferResponse coe -> unsafeReadTagged " ArrayBuffer" rc
261+ BlobResponse coe -> unsafeReadTagged " Blob" rc
262+ DocumentResponse coe -> unsafeReadTagged " Document" rc
263+ JSONResponse coe -> coe $ parseJSON =<< unsafeReadTagged " String" rc
264+ StringResponse coe -> unsafeReadTagged " String" rc
265+ IgnoredResponse coe -> coe $ pure unit
288266
289- type AjaxRequest =
267+ type AjaxRequest a =
290268 { method :: String
291269 , url :: URL
292270 , headers :: Array { field :: String , value :: String }
@@ -297,4 +275,9 @@ type AjaxRequest =
297275 , withCredentials :: Boolean
298276 }
299277
300- foreign import _ajax :: forall e . Fn2 (String -> String -> ResponseHeader ) AjaxRequest (AC.EffFnAff (ajax :: AJAX | e ) (AffjaxResponse Foreign ))
278+ foreign import _ajax
279+ :: forall a
280+ . Fn2
281+ (String -> String -> ResponseHeader )
282+ (AjaxRequest a )
283+ (AC.EffectFnAff (AffjaxResponseT Foreign ))
0 commit comments