Package detail

fetch-parse

moll921.1.0

Fetch API mixin to buffer and parse response bodies. Supports media type patterns for content type specific custom parsers

fetch

readme

FetchParse.js

NPM version Build status

FetchParse.js is a mixin for the Fetch API for browsers and Node.js that automatically buffers response bodies and assigns them as body on the response object (saving you from extra res.text() or res.json() calls). It can also optionally parse response bodies based on the Content-Type header (using MediumType.js for media types).

Installing

npm install fetch-parse

FetchParse.js follows semantic versioning, so feel free to depend on its major version with something like >= 1.0.0 < 2 (a.k.a ^1.0.0).

Using

Pass the native fetch function to fetchParse to get back a new fetch function that will buffer all responses and assign the buffered response body to the body property on the response object. It'll also parse JSON responses (those whose Content-Type matches application/json or */*+json):

var fetchParse = require("fetch-parse")
var apiFetch = fetchParse(fetch)

The above is equal to calling fetchParse with the wildcard media type:

var fetchParse = require("fetch-parse")
var apiFetch = fetchParse(fetch, {"*/*": true})

Now, calling apiFetch will give you back a Promise with a regular Response object, but with the body property assigned to the buffered response body:

apiFetch("/users").then(function(res) {
  // If Content-Type of /users was application/json and it returned
  // an array, you could start using it right there:
  res.body[0].email
})

For built-in parsers that FetchParse.json includes, see below.

Parsers

To configure what media types FetchParse.js buffers and parses, pass an object of media type patterns and trues. The true value there indicates you'd like to use the default parser. If you need a custom parser, see Custom Parsers.

var fetchParse = require("fetch-parse")

var apiFetch = fetchParse(fetch, {
  "text/markdown": true,
  "json": true,
})

FetchParse.js uses MediumType.js's MediumType.prototype.match to match the parser pattern against the response's Content-Type header. The buffering and parsing behavior is dependent on Content-Type because that allows enabling default parsing of every response with {"*/*": true}, but still get text/plain parsed as a string, application/json as a JavaScript object etc.

Default Parsers

Content-Type Description
text/* Calls res.text() and returns a string.
application/json Equivalent to res.json() and returns a parsed object.
*/*+json See application/json above.
application/xml Calls res.text() and returns a string.
*/*+xml See application/xml above.
*/* Calls res.arrayBuffer() and returns an ArrayBuffer.

Shorthands

Aside from regular media type patterns, FetchParse.js has two shorthands for JSON and XML. That's because RFC 6839 specifies standardized suffices for those two in addition to application/json and application/xml. Using json for example saves you from having to specify both patterns explicitly.

Shorthand Types
json application/json, */*+json
xml application/xml, */*+xml

Custom Parsers

To use a custom parser for some media types, pass an object mapping a media type pattern to that parse function. The parse function must take a Fetch.Request object and return a Promise of a body. FetchParse.js will itself assign that to the body property on the response object.

var fetchParse = require("fetch-parse")

var apiFetch = fetchParse(fetch, {
  "text/html": parseHtml,
  "image/*": parseImage,
  "application/vnd.example.model+json": parseModel
})

You can implement parseHtml by first calling Response.prototype.text to get the plain-text version and then creating a DocumentFragment from it:

function parseHtml(res) {
  return res.text().then(function(html) {
    return document.createRange().createContextualFragment(html)
  })
}

For converting bytes of an image to a URL you could later use with <img src="" />, you could call Response.prototype.arrayBuffer and create a Blob URL from it (e.g. blob:d3958f5c-0777-0845-9dcf-2cb28783acaf):

function parseImage(res) {
  return res.arrayBuffer().then(function(body) {
    var blob = new Blob([body], {type: res.headers.get("content-type")})
    return URL.createObjectURL(blob)
  })
}

To parse JSON into a your own model instance, you can first use Response.prototype.json to have it parsed into an object and then instantiate your model with it:

function Model(attrs) { this.attributes = attrs }

function parseModel(res) {
  return res.json().then(function(attrs) { return new Model(attrs) })
}

Browser

Browsers have the Fetch API available at window.fetch:

var fetchParse = require("fetch-parse")
var apiFetch = fetchParse(window.fetch)

Node.js

Node.js doesn't have a built-in implementation of the Fetch API, but you can use any library with a compatible interface, such as my Fetch/Off.js or node-fetch:

var fetch = require("fetch-off")
var fetchParse = require("fetch-parse")
var apiFetch = fetchParse(fetch, "https://example.com")

License

FetchParse.js is released under a Lesser GNU Affero General Public License, which in summary means:

  • You can use this program for no cost.
  • You can use this program for both personal and commercial reasons.
  • You do not have to share your own program's code which uses this program.
  • You have to share modifications (e.g. bug-fixes) you've made to this program.

For more convoluted language, see the LICENSE file.

About

Andri Möll typed this and the code.
Monday Calendar supported the engineering work.

If you find FetchParse.js needs improving, please don't hesitate to type to me now at andri@dot.ee or create an issue online.

changelog

1.1.0 (Nov 20, 2016)

  • Adds text/xml to the list of XML content-types.

1.0.0 (Nov 16, 2016)

  • Renames to FetchParse.js.
  • Adds support for passing in an object of types and parsers.
    For a parsers pass either a function taking a Response object and returning a Promise with the body or true to use the default parser for that type.
  • Removes support for passing in an array of types to use default parsers.
  • Adds XML support.

0.3.0 (Jul 31, 2016)

  • Sets body to what arrayBuffer returns when type not text or JSON.

0.2.1 (Jan 2, 2016)

  • Assigns the body property with Object.defineProperty to work on Fetch implementations that already have body as a getter.

0.2.0 (Dec 17, 2015)

  • Skips parsing again if body already used (res.bodyUsed).
    This also means body won't be set undefined in cases where the Content-Type is not recognized.
  • Allows passing in an array of media types to be read and possibly parsed.
    Only JSON is actually parsed. The rest are read to res.body.
  • Reads text/javascript as regular text, not JSON.
  • Skips parsing JSON if no actual content is returned (such as in response to a HEAD) and sets body to undefined.
  • Sets the body of a response (assigned to err.response) to the invalid JSON should an error occur.

0.1.338 (Dec 11, 2015)

  • Skips parsing when response 304 Not Modified.
    This fixes fetching from servers that send a Content-Type along with 304.
  • Skips parsing when response 204 No Content.
    A fail-safe similar to the above.
  • Sets a non-enumerable response property containing the request's Response on the SyntaxError should JSON parsing fail.

0.1.337 (Dec 11, 2015)

  • Scoped release for personal use and profit.