karet.xhr
v1.0.0
Published
An observable wrapper for XMLHttpRequest using Kefir
Downloads
38
Maintainers
Readme
≡ ▶ Karet XHR ·
This library allows one to declare
XMLHttpRequest
s,
compose them, and observe them through
Kefir
properties. This makes it
easy to implement many kinds of use cases ranging from just getting the response
data to visualizing the progress of non-trivial compositions of ongoing upload
and/or download requests and displaying potential errors.
Examples:
- The Giphy CodeSandbox uses this library to do simple JSON GET requests.
- The GitHub repository search CodeSandbox uses this library to do JSON GET requests and exercises much of the API of this library as an example.
≡ ▶ Contents
- Reference
≡ ▶ Reference
The interface of this library consists of named exports. Typically one just imports the library as:
import * as XHR from 'karet.xhr'
Using this library, one declares observable
XMLHttpRequest
s,
composes them, and then observes the ongoing XHR using
the accessors for the result, overall,
download, and upload state.
≡ ▶ Just give me the data!
If you just want to GET some JSON...
≡ ▶ XHR.getJson(url | {url,[, ...options]}) ~> varies
XHR.getJson
returns an observable that emits the full response
after the XHR has succeeded. In case the XHR produces an
error or times out, the XHR is emitted as an error event. See
XHR.perform
for the options.
Note that this function is provided for simplistic usages where one does not need the full composability and observability advantages of this library.
For example:
I.seq(
XHR.getJson(`https://api.github.com/search/users?q=polytypic`),
R.map(L.get(L.query('html_url'))),
log
)
≡ ▶ Declare
XHRs are declared by specifying all the parameters that affect the execution of
an XHR to XHR.perform
, which then returns an observable
property that can be
subscribed to in order to perform the declared XHR.
≡ ▶ XHR.perform(url | {url[, ...options]}) ~> xhr
XHR.perform
creates an observable
property that represents
the state of an ongoing
XMLHttpRequest
.
The request is started once the property is subscribed to and is automatically
aborted
in case the property is fully unsubscribed from before it has ended. See also
XHR.performWith
and XHR.performJson
.
Only the url
parameter is required and can be passed as a string. Other
parameters have their XHR default values:
| Parameter | Default | Explanation
| --------- | ------- | -----------
| method
| 'GET'
| HTTP request method to use.
| user
| null
| User name for authentication.
| password
| null
| Password for authentication.
| headers
| null
| An array of [header, value]
pairs, a plain object of {header: value}
properties, a Map
, or a Headers
object mapping headers to values.
| overrideMimeType
| undefined
| If specified overrides the MIME type provided by the server.
| body
| null
| A body of data to be sent.
| responseType
| ''
| Specifies type of response data.
| timeout
| 0
| Number of milliseconds or 0
for infinite.
| withCredentials
| false
| Whether cross-site Access-Control
should use credentials.
In addition to a plain object, the argument to XHR.perform
is allowed to be an
observable property or contain observable properties, in which case the property
created by XHR.perform
performs the XHR with the
latest argument values.
Note that typically one does not explicitly subscribe to the property, but one rather computes a desired view of the property, such as a view of the succeeded response, and combines that further into some more interesting property.
WARNING: Setting responseType
to 'json'
is not supported by IE 11. This
library implements a workaround by calling JSON.parse
on the returned data in
case setting responseType
to 'json'
fails. In case the response does not
parse, then XHR.response
returns null
.
≡ ▶ XHR.performJson(url | {url[, ...options]}) ~> xhr
XHR.performJson
is shorthand for XHR.performWith({responseType:
'json', headers: {'Content-Type': 'application/json'}})
.
≡ ▶ XHR.performWith(url | {...options}, url | {...options}) ~> xhr
XHR.performWith
is a curried function that allows one to define a
XHR.perform
like function with default parameters. The
defaults (first parameter) are merged with the overrides (second parameter).
Headers are also merged. See XHR.perform
for the parameters.
For example:
const get = XHR.performWith({responseType: 'json', timeout: 30*1000})
// ...
get(url)
≡ ▶ Compose
Multiple XHRs can be composed together to appear and be treated simply as a single XHR.
≡ ▶ Basic combinators
≡ ▶ XHR.ap(xhrAtoB, xhrA) ~> xhrB
XHR.ap
implements a static land compatible
ap
function for composing succeeding XHRs. The XHRs are performed sequentially.
See also XHR.apParallel
and XHR.apply
.
≡ ▶ XHR.apParallel(xhrAtoB, xhrA) ~> xhrB
XHR.apParallel
implements a static land compatible
ap
function for composing succeeding XHRs. The XHRs are performed in parallel.
See also XHR.ap
and XHR.apply
.
≡ ▶ XHR.chain(A => xhrB, xhrA) ~> xhrB
XHR.chain
implements a static land compatible
chain
function for composing succeeding XHRs.
≡ ▶ XHR.map(A => B, xhrA) ~> xhrB
XHR.map
implements a static land compatible
map
function for composing succeeding XHRs.
≡ ▶ XHR.of(A) ~> xhrA
XHR.of
implements a static land compatible
of
function for composing succeeding XHRs.
≡ ▶ Additional combinators
≡ ▶ XHR.apply((...As) => B, [...xhrAs]) ~> xhrB
XHR.apply
maps the given XHRs through the given function. Unlike with
XHR.ap
, the XHRs are performed in parallel.
≡ ▶ XHR.tap(A => ignored, xhrA) ~> xhrA
XHR.tap
wraps the XHR so that the given action is called with the response
after the XHR has succeeded. If the XHR does not succeed, the action will not
be called.
Note that XHR.tap(action)
is roughly equivalent to
XHR.map(response => {
action(response)
return response
})
≡ ▶ XHR.template([ ... xhr ... ] | { ... xhr ... }) ~> xhr
XHR.template
transforms a nested template of plain arrays and objects possibly
containing XHRs into a XHR. The XHRs are performed in parallel.
≡ ▶ Algebras
Static Land compatible algebras can be used with other Static Land compatible libraries such as Partial Lenses to perform more complex XHRs.
For example:
I.seq(
XHR.performJson(`https://api.github.com/search/repositories?q=user:calmm-js&sort=stars`),
XHR.map(
L.collect([
'items',
L.limit(2, L.flat(L.when(R.has('description')))),
L.pick({
description: 'description',
url: 'svn_url',
issues: 'issues_url'
})
])
),
XHR.chain(
L.traverse(
XHR.Parallel,
issues => I.seq(
XHR.performJson(issues.replace(/{.*}$/, '')),
XHR.map(
L.collect(
L.limit(3, L.flat(L.pick({title: 'title', url: 'html_url'})))
)
)
),
[L.elems, 'issues']
)
),
XHR.result,
log
)
≡ ▶ XHR.IdentityParallel ~> applicative
XHR.IdentityParallel
is a static land compatible
applicative
that manipulates XHRs like XHR.Parallel
or plain data.
≡ ▶ XHR.IdentitySucceeded ~> monad
XHR.IdentitySucceeded
is a static land compatible
monad
that manipulates XHRs like XHR.Succeeded
or plain data.
≡ ▶ XHR.Parallel ~> applicative
XHR.Parallel
is a static land compatible
applicative
that allows one to compose parallel XHR requests. In case any XHR fails, the
composed XHR produces the first failed XHR. In case all XHRs succeed, the
composed XHR produces the combined XHR as the result.
≡ ▶ XHR.Succeeded ~> monad
XHR.Succeeded
is a static land compatible
monad
comprised of the XHR.ap
, XHR.chain
,
XHR.map
, and XHR.of
combinators that allows one to
compose sequences of XHR requests that stop as soon as the first XHR does not
succeed.
≡ ▶ Observe
Ongoing XHRs can be observed both for their varying properties such as the number of bytes transferred and for their results.
≡ ▶ Result
≡ ▶ XHR.hasFailed(xhr) ~> boolean
XHR.hasFailed
returns a possibly observable boolean property of an ongoing XHR
that is true if its HTTP status does not indicate success
or the download or the upload operation has errored or timed
out.
≡ ▶ XHR.hasSucceeded(xhr) ~> boolean
XHR.hasSucceeded
returns a possibly observable boolean property of an ongoing
XHR that is true if the XHR is done, its HTTP status indicates
success, and neither
download or upload has errored
or timed out.
≡ ▶ XHR.result(xhrA) ~> A
XHR.result
returns the response of a succeeded XHR. Note
that XHR.response
allows one to obtain the response before
the XHR is done and even when the XHR has (partially) failed.
≡ ▶ Overall state
≡ ▶ Progression
≡ ▶ XHR.isStatusAvailable(xhr) ~> boolean
XHR.isStatusAvailable
returns a possibly observable boolean property that
tells whether HTTP status and response headers have been received and can be
obtained. See also XHR.status
,
XHR.statusText
,
XHR.allResponseHeaders
, and
XHR.responseHeader
.
≡ ▶ XHR.isDone(xhr) ~> boolean
XHR.isDone
returns a possibly observable boolean property that tells whether
the XHR operation is complete (whether success or failure). See also
XHR.hasSucceeded
.
≡ ▶ XHR.isProgressing(xhr) ~> boolean
XHR.isProgressing
returns a possibly observable boolean property that tells
whether the XHR operation has started, but has not yet ended.
≡ ▶ End state
≡ ▶ XHR.hasErrored(xhr) ~> boolean
XHR.hasErrored
returns a possibly observable boolean property of an ongoing
XHR that is true when either download or
upload has errored.
≡ ▶ XHR.hasTimedOut(xhr) ~> boolean
XHR.hasTimedOut
returns a possibly observable boolean property of an ongoing
XHR that is true when either download or
upload has timed out.
≡ ▶ Errors on failure
≡ ▶ XHR.errors(xhr) ~> [...exceptions]
XHR.errors
returns a possibly observable array of errors from
download and upload. The array will contain 0
to 2 errors.
≡ ▶ Request status
≡ ▶ XHR.status(xhr) ~> number
XHR.status
returns a possibly observable property that emits the
status
after the HTTP status has been received. When called on a non-observable XHR,
readyState
must be 2 or an Error
will be thrown.
≡ ▶ XHR.statusIsHttpSuccess(xhr) ~> boolean
XHR.statusIsHttpSuccess(xhr)
is shorthand for
XHR.isHttpSuccess(XHR.status(xhr))
. Note that HTTP status is usually received
before the download and upload
phases have completed. See also XHR.hasSucceeded
,
XHR.status
and XHR.isHttpSuccess
.
≡ ▶ XHR.statusText(xhr) ~> string
XHR.statusText
returns a possibly observable property of the
statusText
after the HTTP status has been received. When called on a non-observable XHR,
readyState
must be 2 or an Error
will be thrown.
≡ ▶ Data transfer
≡ ▶ XHR.loaded(xhr) ~> number
XHR.loaded
returns a possibly observable property of the sum of
downloaded and uploaded bytes.
≡ ▶ XHR.total(xhr) ~> number
XHR.loaded
returns a possibly observable property of the sum of total
download and total upload bytes.
≡ ▶ Response headers
≡ ▶ XHR.allResponseHeaders(xhr) ~> string
XHR.allResponseHeaders
returns a possibly observable property that emits the
value of
getAllResponseHeaders()
after the HTTP headers have been received. When called on a non-observable XHR,
its readyState
must be 2 or an Error
will be thrown.
≡ ▶ XHR.responseHeader(header, xhr) ~> string
XHR.responseHeader
returns a possibly observable property that emits the value
of
getResponseHeader(header)
for specified header
after the HTTP headers have been received. When called
on a non-observable XHR, its readyState
must be 2 or
an Error
will be thrown.
≡ ▶ Response data
≡ ▶ XHR.response(xhr) ~> varies
XHR.response
returns a possibly observable property that emits the
response
after the download operation of the XHR has completed.
When called on a non-observable XHR, the download operation must be completed or
an Error
will be thrown. See also XHR.result
, and
XHR.responseText
.
≡ ▶ XHR.responseText(xhr) ~> string
XHR.responseText
returns a possibly observable property of the
responseText
property of an ongoing XHR. XHR.responseText
is for observing the received
response data before the data has been completely received. See also
XHR.response
.
≡ ▶ XHR.responseXML(xhr) ~> document
XHR.responseXML
returns a possibly observable property of the
responseXML
property after the XHR has completed. When called on a non-observable XHR, the
download operation must be completed or an Error
will be thrown. See also
XHR.response
.
≡ ▶ Response URL
≡ ▶ XHR.responseURL(xhr) ~> string
XHR.responseURL
returns a possibly observable property of the
responseURL
property after the HTTP headers have been received. When called on a
non-observable XHR, its readyState
must be 2 or an
Error
will be thrown.
≡ ▶ Request parameters
≡ ▶ XHR.responseType(xhr) ~> string
XHR.responseType
returns a possibly observable property of the
responseType
of an ongoing XHR.
≡ ▶ XHR.timeout(xhr) ~> number
XHR.timeout
returns a possibly observable property of the
timeout
property of an ongoing XHR.
≡ ▶ XHR.withCredentials(xhr) ~> boolean
XHR.withCredentials
returns a possibly observable property of the
withCredentials
property of an ongoing XHR.
≡ ▶ Ready state
≡ ▶ XHR.readyState(xhr) ~> number
XHR.readyState
returns a possibly observable property of the
readyState
of an ongoing XHR.
≡ ▶ Download state
≡ ▶ XHR.downError(xhr) ~> exception
XHR.downError
returns a possibly observable property of the
error
property of
an errored XHR.
≡ ▶ XHR.downHasEnded(xhr) ~> boolean
XHR.downHasEnded
returns a possibly observable boolean property that tells
whether the download operation of an ongoing XHR has
ended.
≡ ▶ XHR.downHasErrored(xhr) ~> boolean
XHR.downHasErrored
returns a possibly observable boolean property that tells
whether the download operation of an ongoing XHR has
errored.
≡ ▶ XHR.downHasStarted(xhr) ~> boolean
XHR.downHasStarted
returns a possibly observable boolean property that tells
whether the download operation of an ongoing XHR has
started.
≡ ▶ XHR.downHasCompleted(xhr) ~> boolean
XHR.downHasCompleted
returns a possibly observable boolean property that tells
whether the download operation of an ongoing XHR has been completed
successfully. Note
that this does not take into account the HTTP response status, see
XHR.status
and XHR.isHttpSuccess
.
≡ ▶ XHR.downHasTimedOut(xhr) ~> boolean
XHR.downHasTimedOut
returns a possibly observable boolean property that tells
whether the download operation of an ongoing XHR has timed
out.
≡ ▶ XHR.downIsProgressing(xhr) ~> boolean
XHR.downIsProgressing
returns a possibly observable boolean property that
tells whether the download operation of an ongoing XHR is
progressing.
≡ ▶ XHR.downLoaded(xhr) ~> number
XHR.downLoaded
returns a possibly observable property of the
loaded
property of an ongoing XHR.
≡ ▶ XHR.downTotal(xhr) ~> number
XHR.downTotal
returns a possibly observable property of the
total
property
of an ongoing XHR.
≡ ▶ Upload state
≡ ▶ XHR.upError(xhr) ~> exception
XHR.upError
returns a possibly observable property of the
error
property of
an errored XHR.
≡ ▶ XHR.upHasEnded(xhr) ~> boolean
XHR.upHasEnded
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR has
ended.
≡ ▶ XHR.upHasErrored(xhr) ~> boolean
XHR.upHasErrored
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR has
errored.
≡ ▶ XHR.upHasStarted(xhr) ~> boolean
XHR.upHasStarted
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR has
started.
≡ ▶ XHR.upHasCompleted(xhr) ~> boolean
XHR.upHasCompleted
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR has completed
successfully. Note
that this does not take into account the HTTP response status, see
XHR.status
and XHR.isHttpSuccess
.
≡ ▶ XHR.upHasTimedOut(xhr) ~> boolean
XHR.upHasTimedOut
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR has timed
out.
≡ ▶ XHR.upIsProgressing(xhr) ~> boolean
XHR.upIsProgressing
returns a possibly observable boolean property that tells
whether the upload operation of an ongoing XHR is
progressing.
≡ ▶ XHR.upLoaded(xhr) ~> number
XHR.upLoaded
returns a possibly observable property of the
loaded
property of an ongoing XHR.
≡ ▶ XHR.upTotal(xhr) ~> number
XHR.upTotal
returns a possibly observable property of the
total
property
of an ongoing XHR.
≡ ▶ Auxiliary
≡ ▶ XHR.isHttpSuccess(number) ~> boolean
XHR.isHttpSuccess
returns a possibly observable property of whether the given
numeric property is in the range 2xx of HTTP success
codes.
See also XHR.statusIsHttpSuccess
.
≡ ▶ XHR.isXHR(any) ~> boolean
XHR.isXHR
returns a possibly observable boolean property that tells whether
the given value is a XHR.