npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ftch

v0.1.4

Published

Secure, extendable fetching with telemetry

Downloads

40

Readme

ftch :: Secure, extensible fetching with telemetry

ftch is a Node.js library for doing HTTP requests, focusing on:

  1. Security
  2. Extensibility
  3. Telemetry

Security

Request URLs are often constructed dynamically. To mitigate risk of command-injection attacks, ftch uses URL templates with automatic URL-encoding.

fetch('https://api.example.com/api/users/:id', {
  id: untrustedParams.id
}).then(user => ...);

Extensibility

ftch's extensibility mechanism helps minimize boilerplate.

// declare boilerplate here...
const api = fetch.extend('https://api.example.com/api/', {}, {
  as: 'json',
  accept: 'application/json',
});

// elsewhere...
api('users/:id', { id: params.id })
.then(user => ...);

Telemetry

ftch allows optionally passing in an EventEmitter to collect in-flight telemetry for each request.

// log the progress of every completed request
const telemetry = new EventEmitter();
telemetry.on('request-end', (data, history) => { console.log(history); });
const api = fetch.extend('https://localhost/api/', null, { telemetry });

API

fetch(urlTemplate, params, options)

Makes an HTTP(S) request and returns a promise. By default the returned promise resolves to a Node.js response stream, AKA an http.IncomingMessage. Optionally, it can be made to resolve directly to a buffer, string, or JSON object. Arguments are described below.

urlTemplate

Optional URL template string. If provided, it will be a URL pattern capturing zero or more named variables, for example :id or :version. URL patterns may optionally include scheme, host and port, but named variables may only exist in the path portion of the URL. Examples:

  • https://example.com/api/:version/
  • /users/:id
  • /posts/:id/comments?from=:from&to=:to

At request time, it's executed against the params argument, described below. Note that if params declared in the URL template don't have matching values in the params object, the unexpanded params will be passed through silently to the server. You may opt into stricter behavior by passing requireExpanded: true in options.

params

Optional params object. If urlTemplate (described above) contains any free variables, this argument must be an object whose properties match all those variables. Values are coerced to strings and URL-encoded. null and undefined are treated as empty strings.

options

All options are optional, and the overall options object is also optional. Here are the available options:

  • headers: Object containing HTTP headers.
  • body: The request body. Either a buffer, string, object, or readable stream.
  • as: The type of thing you want the promise to resolve to. Allowed values include 'text', 'json', 'buffer', or 'stream' (default).
  • followRedirects: If true, redirects will be followed. Defaults to true.
  • successOnly: If true, reject the promise for all but 2xx range response status codes (after redirects are followed). Default to true.
  • method: HTTP method to use. Defaults to 'GET'.
  • query: An object containing query string params that will be added to the request URL. If the request URL already contains a query string, these will be merged in.
  • requireExpanded: If truthy, every :param in urlTemplate is required to have a matching value in the params object. By default, unexpanded params are silently passed through.
  • telemetry: A node EventEmitter object which you provide. ftch will emit events on this object for the progress and timing of the request. It's then your responsibility to listen for events on this object.

fetch.extend(urlTemplate, params, options)

Returns a function with extended defaults. Consider these scenarios:

const parent = require('ftch');

// scenario 1
parent(url, params, opts);

// scenario 2
const child = parent.extend(url, params, opts);

// scenario 3
child(url, params, opts);

When parent is called in scenario 1, the given (url, params, opts) is merged into a set of global defaults, using the merge algorithm described below. The result is used to make the request and then discarded.

When parent.extend is called in scenario 2, the given (url, params, opts) is merged into the above-mentioned set of global defaults, using the above-mentioned merge algorithm. The result is not discarded, but rather becomes defaults for subsequent calls on child.

When child is called in scenario 3, the given (url, params, opts) is merged into the above-mentioned child defaults. The result is used to make the request and then discarded.

The chain continues as extend is called on subsequent children.

The Merge Algorithm

urlTemplate1 <= urlTemplate2

Since URL templates are valid URLs, node's URL resolution algorithm is used here:

const mergedUrl = url.resolve(urlTemplate1, urlTemplate2);

params1 <= params2

A standard JavaScript object assign is used here:

const mergedParams = Object.assign({}, params1, params2);

options1 <= options2

Options merge using one of three strategies:

  • overwrite: next replaces prev.
  • object-assign: Object assign prev <= next.
  • array-push: next is pushed onto an array containing all prev values.

Here's how each option gets merged:

  • headers: object-assign
  • body: overwrite
  • as: overwrite
  • followRedirects: overwrite
  • successOnly: overwrite
  • method: overwrite
  • query: object-assign
  • telemetry: array-push

Additionally, any of the following properties found on the options object are passed through to the underlying node.js request: family, auth, agent, pfx, key, passphrase, cert, ca, ciphers, rejectUnauthorized, secureProtocol, and servername. Docs for these can be found here and here. All of these extend using the above-mentioned overwrite strategy.