Skip to content

Main API

Eugene Lazutkin edited this page Nov 26, 2019 · 15 revisions

io()

io(url|options) takes a single argument, which can be a string or an object. If it is an object, the following properties can be processed:

  • url is the only required property. It is a URL of an endpoint we deal with.

The rest of the properties are all optional with reasonable defaults:

  • method is an HTTP method (including PATCH) as a string. Default: 'GET'.
  • query is a query dictionary (a key/value hash), which is used to form a query part of URL after '?'. The values of the dictionary should be strings, or arrays of strings to form multiple values with the same key. If URL already contains a query part, it is added as-is without checking for duplicates. Default: none.
  • data is a data object to send. For GET method it is assumed to be a query object if query is not specified. For all other requests, it is assumed to be a payload. If data is an object of FormData, ArrayBuffer, Blob, or Document, it is sent as-is. Otherwise, if Content-Type is application/json or missing, data is assumed to be a JSON object and stringified. In all other cases it is assumed to be a preformatted value, and send as is. Default: none.
  • headers is a dictionary (a key/value hash), which is used to set request headers. The values of the dictionary should be strings, or arrays of strings to form multiple values with the same key. Default: none, but if there is no Accept header, it is set to application/json.

The next batch of properties is directly related to an underlying XHR request:

  • user is a user name as a string to be sent with the request. Default: not sent.
  • password is a password as a string. It is used only if user is specified. Default: ''.
  • timeout is a wait time for a request in milliseconds as a number. Default: not set.
  • responseType is a requested response type as a string. It can be: 'json', 'arraybuffer', 'blob', 'document', 'text', or ''. Essentially it defines an automatic conversion of a received response in response property of XHR, which is used by io() to return a value. Default: not set.
  • withCredentials is a Boolean flag for cross-origin requests. Default: not set.
  • mime is a string used to override a returned MIME type in Content-Type response header. Default: not set.
  • onProgress() is a function callback, which could be called to inform about progress. Warning: not all implementations support progress reports. The callback can be called with an object, which has the following properties:
    • xhr is the underlying XHR object or its reasonable approximation.
    • options is an object used to initiate the I/O request.
    • event is a native event object corresponding to the progress update.
    • lengthComputable is a boolean flag. If it is falsy the I/O request is indeterminable. Otherwise, we have a total.
    • loaded is a number that represents a processed part of the request.
    • total is a number that represents all data of the request.
    • upload is a boolean flag. It is truthy if it is a report on upload and falsy on download.
  • onDownloadProgress() is a callback similar to onProgress() but it is called only for download progress events.
  • onUploadProgress() is a callback similar to onProgress() but it is called only for upload progress events.
  • signal is an object that can abort an I/O request. It can be a promise (then-able), which aborts a request when resolved, or an interface like AbortSignal with "abort" event.

The next batch of properties used to replace default processing of received response:

  • returnXHR is a Boolean flag. If true an XHR object is returned instead of received data. It is useful if we want to inspect headers or raw data. Default: false.

  • processSuccess(result) is a function that receives a result object for processing and returns either a data object or a rejected promise. Default: io.processSuccess() (see below for more details).

  • processFailure(error) is a function that received an error object for processing, and it should return either a data object or a rejected promise. It will be called when I/O was unsuccessful, or processSuccess() returned an error. Default: io.processFailure() (see below for more details).

The next batch of properties is used for advanced processing with plugins:

  • wait is a Boolean flag that indicates our interest in this I/O request, but we don't want to initiate it at this point. Requires track plugin. Default: false.
  • bundle is a Boolean flag that allows bundling this request. Requires bundle plugin.
  • cache is a Boolean flag that allows using cache for this request. Requires cache plugin.
  • track is a Boolean flag that allows tracking this request (required for bundling). Requires track plugin.
  • mock is a Boolean flag that allows mocking this request. Requires mock plugin.

See respective plugins for more details on those properties and their default values.

If a string is specified as the only argument of io(), it is assumed to be a URL. It will be treated as:

// io(url) =>
io({
  url: url,
  method: 'GET'
})

io() returns a promise:

io('http://example.com').then(
  function (data) {
    console.log('We got data:', data);
  },
  function (error) {
    console.log('We failed with', error.xhr.status, '=>', error.xhr.statusText);
  }
);

Don't forget to consult the cookbook to see working snippets solving simple real-world problems:

Returned values

In case of success io() tries to return already decoded values from a JSON string, an XML string, or a string response itself otherwise.

  • If responseType is set, an automatically decoded response is returned as per XMLHttpRequest spec.
  • If no data is returned (responses with 204 status code, or responses for HEAD requests), an undefined is used as a returned value.
  • If returnXHR is set, the whole XHR object is returned.

In case of failure io() returns an error object (all three types are described below) with the following properties:

  • xhr — an XHR object as is. It can be null if transport does not use XHR.
  • options — a request description described above.
  • event — a raw event object, which describes a problem, or null, if not used.

Warning: in some cases instead of XHR io() can return FauxXHR object, which is a simulation of XHR. In most cases, it should be a problem.

Convenience methods

io.get(url|options, [query])

io.get() initiates a GET request. It takes two arguments:

  • url is a URL as a string.
  • options is an options object described above (see io()).
  • query is an optional dictionary to form a query string (see data above in io()).

Either url or options should be specified.

The returned value is a promise (see io() for details).

io.head(url|options, [query])

io.head() initiates a HEAD request, and as such, it returns no data. Otherwise, it is identical to io.get().

io.post(url|options, [data])

io.post() initiates a POST request. It takes two arguments:

  • url is a URL as a string.
  • options is an options object described above (see io()).
  • data is an optional data object (see data above in io()).

Either url or options should be specified.

The returned value is a promise (see io() for details).

io.put(url|options, [data])

io.put() initiates a PUT request. Otherwise it is identical to io.post().

io.patch(url|options, [data])

io.patch() initiates a PATCH request. Otherwise it is identical to io.post().

io.remove(url|options, [data])

io.remove() initiates a DELETE request. Otherwise it is identical to io.post().

io['delete'](url|options, data)

The other way to initiate a DELETE request is to call io['delete'](), which is less convenient than calling io.remove(), because delete is a reserved word in JavaScript (not a problem nowadays). io.remove() is an alias of this function.

io.del(url|options, [data])

Yet another alias of io.delete().

io.options(url|options, [query])

io.options() initiates an OPTIONS request, and as such, it returns no data. Otherwise, it is identical to io.get().

Exposed properties

The following properties are available to customize all aspects of I/O handling.

io.Result

It is an object constructor used to indicate a result of an I/O request. It takes three arguments:

  • xhr is an underlying XHR object. It can be null in certain cases, e.g., for JSON-P calls.
  • options is an original options object, which initialized this request.
  • event is an event object, which finished the request and possibly provides more information about the error. It can be null.

All those arguments are exposed as properties on an object.

io.FailedIO

It is an object constructor based on io.Result used to indicate an underlying I/O error.

Objects of this type is used for generic I/O errors when XHR has failed to start. It is exposed so the user can construct its own errors, or use it with instanceof operator.

io.FailedIO is used as a base class for other io errors.

io.TimedOut

It is a constructor based on io.FailedIO with the same arguments. It is used to indicate timeout errors.

io.BadStatus

It is a constructor based on io.FailedIO with the same arguments. It is used to indicate server status errors.

io.FauxDeferred

It is a deferred object constructor (see heya-async wiki for explanations) made out of the standard Promise.

io.Deferred

It is a deferred object constructor used by io to construct promises. Default: io.FauxDeferred.

While io.FauxDeferred is very compact, it is not always a suitable solution: it is based on Promise, which is not always available on modern browsers (see Can I use Promises?). Theoretically, io can work with any compliant deferred, it was extensively tested with FastDeferred and Deferred of heya-async and can use its extended features: progress callbacks, and cancellation of I/O requests. Import a deferred of your choosing, and assign it to io.Deferred.

io.prefix

This property is related to making unique keys out of options, which can be used to track calls by track, cache, and other plugins. It defines what string prefix to use when making a key. Default: 'io-'.

io.makeKey(options)

This function defines a function that takes options and returns a unique key as a string.

The default concatenates io.prefix value with a method name, dash, and a url.

For example, when requesting http://example.com/ with GET, it will produce the following key: 'io-GET-http://example.com/'.

io.makeQuery(dict)

This function takes a key/value dictionary object and returns a correctly encoded query string. Values are assumed to be strings or arrays of strings. The latter is used to form multiple values with the same key.

io.buildUrl(options)

This function takes options object and returns a URL string for that I/O request. It may include a query string derived from query and data properties depending on method.

io.processOptions(options)

This function is called to transform io()'s options. Before calling this function, if options is a string, it is assumed to be a URL, and the new options object is formed:

{
  url: url
}

It ensures that the argument of io.processOptions() is always an object.

The default implementation returns its argument as is.

This function is exposed solely to be replaced or augmented (AOP-style) by users to accommodate unique requirements.

io.processSuccess(result)

It is called when I/O itself was successful. It will be called even if a server returned an error. It is its job to detect such errors and respond accordingly.

A result object can be of io.Result. In this case, it has three properties:

  • xhr is an underlying XHR object to process.
  • options is an original options object, which initialized this request.
  • event is a load event object, which finished the request. It can be null.

Any other value is returned as-is.

This function is the first in the promise's then-chain. It performs the following actions:

  • If status is not in 2XX range, it returns a rejected promise with a value of io.BadStatus. That object will have all those three properties mentioned above.
  • If options.returnXHR was set, the XHR object will be returned.
  • If the response had no body, undefined will be returned.
  • If responseType was set, it will return response of an XHR object.
  • Runs custom MIME processors sequentially (see io.mimeProcessors below).
  • If responseXML is set, its value will be returned.
  • If the returned Content-Type is application/json, the received string will be parsed as a JSON object, which will be subsequently returned.
  • Otherwise responseText of an XHR will be returned.

This function can be overwritten for individual requests in io()'s options as processSuccess property.

io.processFailure(error)

By default an error object can be of three types:

  1. io.FailedIO, when I/O failed to happen.
  2. io.TimedOut, when timeout was specified, but I/O did not finish in a specified time.
  3. io.BadStatus, when everything was fine, but our response indicates a logical error, such as a bad status from a server.

An error object has the same three properties as the result object of io.processSuccess().

This function is the first in the promise's catch-chain right after io.processSuccess(). It returns a rejected promise resolved to an XHR object of the failed request. If XHR is not available (e.g., for JSON-P requests), null is used.

This function can be overwritten for individual requests in io()'s options as processFailure property.

io.processData(xhr, options, data)

This procedure is used to configure an XHR object and return a data object ready to be sent out. Arguments:

  • xhr is an XHR object that will be used for a request.
  • options is an original options object, which initialized this request.
  • data is an object from options.data or null.

The default implementation performs the following actions:

  • Checks headers for Accept header. If it is not set, sets it to application/json.
  • Checks the method. If it is GET or missing (GET is assumed), returns null meaning "no payload".
  • Runs custom data processors sequentially (see io.dataProcessors below).
  • If data is of following types: FormData, ArrayBuffer, Blob, or Document, it returns data as is.
  • Checks headers for Content-Type.
    • If it is application/json, data is assumed to be JSON, it is stringified and returned.
    • If it is missing, Content-Type is set to application/json, data is assumed to be JSON, it is stringified and returned.
  • Otherwise data is returned as-is.

This function is exposed solely to be replaced or augmented (AOP-style) by users to accommodate unique requirements.

io.prepareRequest(options)

It takes an I/O request's options, and returns an object with three properties:

  • url — a real URL as prepared by io.buildUrl().
  • key — a unique key as prepared by io.makeKey().
  • data — a data payload object, or null depending on what we need to send with a request.

Calculating this triplet is more efficient than calling individual functions. To improve performance, it is calculated only once per request. While io.buildUrl() is used directly, other properties are calculated inline using similar algorithms.

io.dataProcessors

This is an array (initially empty). Each even element is a constructor, which is used by instanceof operator to match the data instance. If it is matched, then the corresponding odd element is a function with the same signature as io.processData() described above. It returns a new data object using xhr, options, and data as inputs. It can explore and set headers.

io.mimeProcessors

This is an array (initially empty). Each even element can be one of these:

  • String to match MIME types with ===.
  • Regular expression object to match MIME types with RegExp.test().
  • Function, which takes the MIME type as a string, and returns a truthy value, if there is a match, and a falsy value otherwise.

If it is matched, then the corresponding odd element is a function that takes two parameters:

  • xhr is an underlying XHR object to process.
  • contentType is a MIME type as string.

If the function returns a non-undefined value, it will be ultimately returned to the user code as a result of I/O. Otherwise, the default processing continues, but no other MIME processors are going to be tried.

io.xhrTransport(options, prep)

The implementation of XHR-based transport to process HTTP verbs. It returns a promise, and takes following parameters:

  • options — an options object, which describes an I/O request.
  • prep — an optional helper object made by io.prepareRequest().

io.defaultTransport

The current transport used to process HTTP verbs. Default: io.xhrTransport.

io.transports

It is a dictionary object for transports. Its keys correspond to transport names, while values are transport handling functions. See Transport for more details.

io.makeVerb(value, property)

A helper function that creates a function that augments an options object with a method or transport:

  • value — a value to assign.
  • property — a property name to assign. Default: 'method'.

Examples:

// make a new HTTP verb:
io.doit = io.makeVerb('DOIT');

// make a transport helper:
io.jsonpi = io.makeVerb('jsonpi', 'transport');

// use them:
async.par(
  io.doit('/a', {q: 1}),
  io.jsonpi('/b')
).then(function () {
  console.log('ALL DONE!');
});

io.request(options, prep, level)

This is the main function that processes an I/O request. The parameters:

  • options — an options object, which describes an I/O request.
  • prep — an optional helper object made by io.prepareRequest(). It will be recreated from options, if not specified.
  • level — an optional index number, which is used to start checking services. If not specified, the services will be checked to start with the highest priority one. It is used by services to skip part of services, which already refused to accept this request.

The function returns a promise.

The algorithm:

  • Check services by priority from the highest to the lowest.
    • As soon as service returns a promise, return it.
  • Check transports, and call a match.
  • Otherwise try to make an XHR call.

io.services

An array of service records sorted by priority from the lowest to the highest. Each record is an object with the following properties:

  • name — a unique service name.
  • priority — a number usually from 0 to 100. The higher priority, the earlier a service is consulted.
  • callback — a service handler function. See Service for more details.

io.services is a registry of active services, and used by io.request().

io.attach(service)

Includes a service into the registry. service is an object described above in io.services.

io.detach(name)

Removes a service from the registry by its name.

io.AbortRequest

It is a parameterless constructor, which returns an object with two properties:

  • abort() is a method, which should be called to abort a request. It takes no parameters and returns no values.
  • promise is a promise object, which becomes resolved when abort() is called.

This class is modeled after AbortController.

Clone this wiki locally