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

@krutoo/fetch-tools

v0.1.0

Published

Set of utilities for JS fetch function

Downloads

119

Readme

Fetch tools

Set of utilities for JavaScript Fetch API.

Goals

  • do not change fetch behavior, just add some features
  • ability to run in browser, Node.js, Deno, Bun, WinterJS (...any runtime that implements Fetch API)
  • zero dependencies

Installation

# in Node.js via NPM
npm add @krutoo/fetch-tools

# in Deno via JSR
deno add @krutoo/fetch-tools

# in Bun
bun add @krutoo/fetch-tools

Usage

Creating fetch with some extra features.

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { defaultHeaders, log, validateStatus } from '@krutoo/fetch-tools/middleware';

// configure your own fetch...
const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    // validate status (like in axios)
    validateStatus((status) => status >= 200 && status < 300),
    // add default headers
    defaultHeaders({
      'user-agent': 'test',
    }),
    // log request stages (before request, after response, on catch)
    log({
      onCatch: ({ error }) => console.error(error),
    }),
  ),
);

// ...and using it like normal fetch
myFetch('posts/1')
  .then((res) => res.json())
  .then((data) => console.log(data));

Middleware

Middleware are just functions and you can write your own.

async function myMiddleware(request, next) {
  try {
    // [do something before request here]

    const response = await next(request);

    // [do something after response here]

    return response;
  } catch (error) {
    // [do something on error here but don't forget throw error or return response]

    throw error;
  }
}

Builtin middleware

validateStatus

Returns a middleware that will validate status.

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { validateStatus } from '@krutoo/fetch-tools/middleware';

const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    // fetch promise will be rejected when status is not valid
    validateStatus((status) => status >= 200 && status < 300),
  ),
);

defaultHeaders

Returns a middleware that will set default headers to request.

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { defaultHeaders } from '@krutoo/fetch-tools/middleware';

const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    // all requests will contain declared headers
    defaultHeaders({ 'user-agent': 'spy' }),
  ),
);

log

Returns a middleware that will log phases by handler.

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { log } from '@krutoo/fetch-tools/middleware';

const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    // each phase of request will be logged
    log({
      onRequest({ request }) {
        console.log(request);
      },

      onResponse({ request, response }) {
        console.log(response);
      },

      onCatch({ request, error }) {
        console.error(error);
      },
    }),
  ),
);

jwt

Returns simplest JWT middleware. This middleware will add Authorization header to each request that matches the condition.

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { jwt } from '@krutoo/fetch-tools/middleware';

const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    jwt({
      // Access token
      token: '...',

      // Determines whether to add a header
      filter: (req) => req.url.includes('/api/'),
    }),
    // ...or like this
    jwt({
      // "token" can be function that should return string or null or Promise<string | null>
      token: () => getJwtFromSomewhere(),
    }),
  ),
);

retry

Returns a middleware that will retry the request until either:

  • or the retries count is exceeded;
  • or until a successful response is received.
import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { retry } from '@krutoo/fetch-tools/middleware';

const myFetch = configureFetch(
  fetch,
  applyMiddleware(
    retry({
      count: 5,
      whenNotOk: true,
      whenCatch: false,
    }),
  ),
);

proxy

Returns simple proxy middleware. Useful for servers based on Fetch API.

import { applyMiddleware } from '@krutoo/fetch-tools';
import { proxy } from '@krutoo/fetch-tools/middleware';

const enhance = applyMiddleware(
  proxy({
    // pathname(s) of incoming request URL which will be proxied
    filter: ['/api/v2/', '/api/v3/'],

    // define target URL
    target: 'https://www.my-site.com/',
  }),
);

Deno.serve(
  enhance((req) => {
    return new Response('<h1>Main page</h1>');
  }),
);

Server utilities

You can use utils for simply configure your HTTP server.

In Deno

import { router } from '@krutoo/fetch-tools/server';

const handler = router
  .builder()
  .get('/', () => new Response('Home page'))
  .put('/about', () => new Response('About page'))
  .post('/news', () => new Response('News page'))
  .all('/stats', () => new Response('Some stats'))
  .build();

await Deno.serve({
  port: 8080,
  handler: handler,
});

In Bun

import { router } from '@krutoo/fetch-tools/server';

const handler = router
  .builder()
  .get('/', () => new Response('Home page'))
  .put('/about', () => new Response('About page'))
  .post('/news', () => new Response('News page'))
  .all('/stats', () => new Response('Some stats'))
  .build();

Bun.serve({
  port: 8080,
  fetch: handler,
});

In Node.js (node:http or express)

Currently there is no builtin server implementation based on Fetch API in Node.js.

It is possible to use adapter for node:http or express from @whatwg-node/server.

import { router } from '@krutoo/fetch-tools';
import { createServer } from 'node:http';
import { createServerAdapter } from '@whatwg-node/server';

const handler = router
  .builder()
  .get('/', () => new Response('Home page'))
  .put('/about', () => new Response('About page'))
  .post('/news', () => new Response('News page'))
  .all('/stats', () => new Response('Some stats'))
  .build();

const server = createServer(createServerAdapter(handler));

server.listen(8080);

Middleware for servers

You can use middleware for server handlers too:

import { applyMiddleware } from '@krutoo/fetch-tools';
import { router } from '@krutoo/fetch-tools/server';
import { log } from '@krutoo/fetch-tools/middleware';

const enhance = applyMiddleware(
  log({
    onCatch: ({ error }) => console.error(error),
  }),
);

const handler = router
  .builder()
  .get('/', () => new Response('Home page'))
  .put('/about', () => new Response('About page'))
  .post('/news', () => new Response('News page'))
  .all('/stats', () => new Response('Some stats'))
  .build();

Bun.serve({
  port: 8080,
  fetch: enhance(handler), // just wrap handler to enhancer for apply middleware
});

Working with HTTP cookie on server

Cookies can be used in different ways on the server.

Browser like behavior

If you want to imitate browser behavior as much as possible in terms of working with cookies, you can use @krutoo/fetch-tools together with fetch-cookie.

To use fetch-cookie as an middleware, follow these instructions.

Microfrontends

Server part of the microfrontend can make requests to some HTTP API on behalf of the user, sending his cookies in requests.

In this case you can use just defaultHeaders middleware:

import { applyMiddleware, configureFetch } from '@krutoo/fetch-tools';
import { defaultHeaders } from '@krutoo/fetch-tools/middleware';

// example of server handler
async function handler(request: Request) {
  const myFetch = configureFetch(
    fetch,
    applyMiddleware(
      // forward cookie from incoming request to all outgoing requests
      defaultHeaders({ cookie: request.headers.get('cookie') }),
    ),
  );

  // this request will contain cookies from the incoming request
  const orders = await myFetch('http://something.com/api/user/orders').then(
    (res) => res.json(),
  );

  return new Response(JSON.stringify({ orders }), {
    'content-type': 'application/json',
  });
}

To do

  • ~~JWT middleware~~
  • ~~retry middleware~~
  • ~~ability to use with Bun's Bun.serve and Deno's serve from std/http~~