Vanilla-ish web component wrapper around the fetch method.

Published on webcomponents.org

<xtal-fetch>

API

Single Requests

<xtal-fetch> is a vanilla web component wrapper around the fetch api. It is inspired by Polymer's <iron-ajax> component. But this component has no legacy Polymer dependencies, is a thin transparent wrapper around the native fetch api, and supports some alternative functionality not supported by iron-ajax. However, xtal-fetch is compatible with Polymer's powerful binding mechanism.

Is this a valid use case for a web component?

NB: The Polymer/Lit team now touts providing the kind of fetch functionality found in this component, not with a web component, but rather with directives.

Within the confines of a code-centric web component (which alas is becoming the dominant paradigm for the time being), I concede that the boilerplate savings this component provides is also provided by their directives. Possibly caching is the only feature this component supports which the directives showcased in the video don't yet support. But I'm sure that could be worked in if it hasn't already.

The only three admittedly weak arguments in favor of using this component inside a lit-element based component are:

  1. What makes the lit-element "tick" could be more transparent using this component, vs directives, as far as inspecting the component using browser dev tools.
  2. I'm not a stickler for "separation of concerns" by any means, but there is really no separation of concerns whatsoever when using said directives.
  3. The claim that the markup is "declarative" becomes even less tenable in my mind.

On the other hand, I recognize that the syntax is more compact, and would likely perform (slightly?) faster.

Watching the video also made me realize that the implementation of abort, added in a recent release, was incomplete. With this latest release, if a new request is made, if there's a pending request, it will be aborted. Multiple requests now supports abort as well.

Referencing

In order to keep the size of the download(s) as small as possible, the functionality of this component is broken down into three subcomponents. xtal-fetch-get just supports basic get requests, has no support for error handling. It requires a browser that supports ES6 Modules. xtal-fetch-req supports everything xtal-fetch supports,except parallel multiple entity fetch requests.

If you want to just keep things simple and include everything, or need to support browsers that don't support ES6 Modules you can use xtal-fetch.js. It can use a classic script reference or a module reference. It weighs 2.5 KB minified and gzipped.

All the evergreen browsers support fetch. For IE11, a polyfill should be used.

An example of such a polyfill can be found here. This was extracted from the Financial Times Polyfill service. It contains additional polyfills recommended for supporting most ES6 features.

To use <xtal-fetch>

yarn add xtal-fetch

or

npm install xtal-fetch

or

<script src="https://cdn.jsdelivr.net/npm/xtal-fetch@0.0.46/build/ES6/xtal-fetch.js"></script>

or

<script src="https://unpkg.com/xtal-fetch@0.0.46/build/ES6/xtal-fetch.js"></script>

As mentioned, if you don't need all the functionality of xtal-fetch.js, replace the above links with xtal-fetch-get or xtal-fetch-req (and modify the tag name accordingly.)

Core functionality

To make a fetch request, you need to add the fetch attribute, and specify an href value:

<xtal-fetch fetch href="https://myDomain/myPath/mySubpath"></xtal-fetch>

It may seem somewhat redundant to need to add the fetch attribute (being that the component is called "xtal-fetch"). However, this attribute / property serves a useful purpose: It can block requests until a sanity check is satisfied, such as the requirement of a binding parameter:

<!-- Polymer Notation -->
<xtal-fetch fetch="[[myBinding]]" href="https://myDomain/myPath/[[myBinding]]"></xtal-fetch>

This will prevent a (typically cancelled) request from going through, until the binding needed for the href is available. Debouncing is also supported to help avoid duplicate calls due to complex bindings.

For more complex sanity checks / validation logic, the fetch property could, of course, refer to a computed property coming from the hosting [Polymer?] component (if applicable).

xtal-fetch also has a property, disable, that prevents requests from going through. Kind of the opposite of the fetch property.

In the event that multiple xtal-fetch tags share the same base URL, xtal-fetch supports the use of the link rel="preconnect" tag to specify the base url. A unique ID should be given to that link, inside the document.head tag:

<link rel="preconnect" id="myAPIBaseUrl" href="https://myDomain/api/">

Then you can refer to this base URL thusly:

<xtal-fetch base-link-id="myAPIBaseUrl"  href="myPath/[[myBinding]]"></xtal-fetch>

The base url will be prepended to the href property.

One can specify whether the result should be parsed as JSON, or left as text, using the "as" attribute:

<xtal-fetch fetch href="https://myDomain/myPath/mySubpath" as="json"></xtal-fetch>

Possible values for as are "json" and "text."

The results of the fetch can be inserted inside the xtal-fetch tag, becoming a glorified client-side "include":

<xtal-fetch fetch href="https://myDomain/myPath/mySubpath" as="text" insert-results></xtal-fetch>

Note, though, that if using a relative path for href, it will be relative to the url of the hosting page, not the url of the component definition.

Caching

xtal-fetch supports caching, by setting attribute/property cache-results/cacheResults to true.

Abort support

Set the "abort" property of your xtal-fetch instance to true in order to "manually" abort any running request. The component also automatically aborts request if a new request is made before the previous request finished.

Fine tuning

It is often mistakenly assumed that the "fetch" api only supports get, not post. This is in fact not the case. The second parameter of the fetch function is often referred to as the reqInit parameter, and it can specify a method of "post", request headers, and the body of a post request, and much more. This component simply passes the reqInit property into the api, unaltered:

<xtal-fetch fetch href="api/persistService/id/[[id]]" as="json" 
result="{{people}}" req-init="[[myRequestConfig]]"></xatl-fetch>

myRequestConfig could be initialized inside the containing component, or come from another component that posts to "myRequestConfig".

In order to avoid doing a premature fetch, before the reqInit binding takes place, one can specify the attribute: reqInitRequired:

 <xtal-fetch fetch href="api/persistService/id/[[id]]" as="json" 
 result="{{people}}" req-init="[[myRequestConfig]]" req-init-required></xatl-fetch>

Although this could be done with boilerplate code using the fetch property, it is such a common need that this additional attribute is added for this specific purpose.

The reqInit property is also an attribute, allowing you to specify common properties inline:

<xtal-fetch fetch href="https://myDomain/myPath/mySubpath" req-init='{"credentials": "same-origin"}' as="json"></xtal-fetch>

Multiple requests

<xtal-fetch> allows for spawning multiple fetch requests tied to an array of entities. This is often useful when drilling down from some parent entity ('customer', e.g.) to multiple 1-n relations ('purchases', e.g.)

The syntax for this is meant to be readable:

<xtal-fetch  fetch href="api/customer/[[id]]/purchase/:id" for-each="id" in-entities="[[purchases]]" 
              as="json"  set-path="purchase_detail" on-fetch-complete="refreshDetail"></xtal-fetch>

set-path specifies the property name in each entity, used to store the fetched entity detail (json or text specified by "as" just like before).

Note that xtal-fetch issues a "fetch-complete" event after all the fetches are completed.

One can enable caching of the same href value using the cache-results attribute.

Like the Polymer iron-ajax inspiration, the debounce-duration attribute specifies how much to wait for the request to "settle down" before proceeding.

Install the Polymer-CLI

First, make sure you have the Polymer CLI and npm (packaged with Node.js) installed. Run npm install to install your element's dependencies, then run polymer serve to serve your element locally.

Viewing Your Element

$ polymer serve

Running Tests

WIP.

Install

Link to this version
ImportedReleased 23 June 2018MIT License
Framework Support
Polymer 3.0+
Browser Independent
Install with
npm install xtal-fetch"@0.0.34"
Run the above npm command in your project folder. If you have any issues installing, please contact the author.
Release notes - Version 0.0.34

Dependencies

  • @polymer/polymer#^3.0.0
  • xtal-latx#0.0.13