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

fetchp

v0.0.44

Published

Not an another HTTP client but a fetch wrapper with fluent API and superpowers

Downloads

14

Readme

fetchp

npm version npm download license

Table of Contents

What is the fetchp/fetch+?

fetchp is "not an another HTTP client but a fetch wrapper with fluent API and superpowers". The trailing "p" is a means for "plus".

Why? What's the motivation?

fetch is a standard Web API that's already supported by modern browsers, Deno, node.js, bun and etc.

We don't need another HTTP client. Still, a web API's target audience is very broad. APIs like fetch are being designed carefully by the community and organizations to be used by the general public. Any design mistake can cause lots of unrecoverable problems. For this reason, they're keeping it simple and running away from the idea of increasing the extra features they can cover.

So, if you want to use fetch, you may need to wrap it with some extra functionality from time to time. For example, if you call it from a React web project, checking its loading state almost is a must. Or, if you're writing automated tests for your application, you need to mock the fetch API.

This is where fetchp comes into play. It still uses fetch's native implementation that brought you by browsers or runtimes themselves, but in the meantime, it wraps the fetch to provide extra functionality for developers.

Fetchp tries to assemble some tools that are useful and reusable for most of the projects that fetch doesn't provide.

Moreover, since fetchp is a JavaScript module / npm package, it also follows the semantic versioning and its API can be evolved in the future without breaking any project.

Superpowers

  • [x] Fluent API
  • [x] React Hooks API
  • [x] Abortable requests
  • [x] Testing-friendly
  • [x] Mocking response for requests (not just for tests)
  • [x] Setting Base URL
  • [x] Automatic deserialization/parsing by content-types
  • [x] Prefetching and local caching
  • [x] On-demand fetching
  • [x] Fetch status
  • [x] Multiple instances of fetchp
  • [x] TypeScript Type Support

More to come see Todo List section.

Quick start

Execute npm install fetchp or yarn add fetchp to install fetchp and its dependencies into your project directory.

Usage

Basic HTTP Request For Text-Based Data

import { fetchp } from "fetchp";

// you don't need to await request
const req = fetchp.request("GET", "https://www.google.com/");

// you may await data instead...
// once your request is completed, it will return a string
console.log(await req.data);

Basic HTTP Request For JSON Data

import { fetchp } from "fetchp";

const req = fetchp.request("GET", "https://jsonplaceholder.typicode.com/posts");

// since your request will return a json, req.data will return an object
console.log(await req.data);

Caching Requests

import { fetchp, FetchpStatus } from "fetchp";

const doReq = () =>
  fetchp.request(
    "GET",
    "https://jsonplaceholder.typicode.com/posts",
    { cacheRequest: true },
  );

const response1 = doReq();
await new Promise((r) => setTimeout(r, 1000));
const response2 = doReq();

// you can check equality afterwars
assert(await response1.data === await response2.data);

Aborting a Request

import { fetchp, FetchpStatus } from "fetchp";

const req = fetchp.request("GET", "https://jsonplaceholder.typicode.com/posts");

// abort it after 500 milliseconds
setTimeout(() => req.abortController.abort(), 500);

// you can check status afterwars
assert(req.status === FetchpStatus.CANCELED);

Setting a Base URL for Requests

Assume that you're working with a single API on the backend, and you don't want to repeat yourself by concatenating endpoint URL strings in each request you make.

import { fetchp } from "fetchp";

fetchp.setBaseUri("https://jsonplaceholder.typicode.com");

const req = fetchp.request("GET", "/posts");

console.log(await req.data);

Middlewares / Hooks

Assume that you're need to add additional headers to each request you make.

import { fetchp, FetchpHookType } from "fetchp";

fetchp.hooks.add(
  FetchpHookType.BuildRequestHeaders,
  (headers) => headers.set("Authorization", `Bearer ${getIdToken()}`);
);

const response = fetchp.request(
  "GET",
  "https://localhost/api/some-restricted-endpoint"",
);

Middlewares / Hooks (URL Based)

Assume that you're need to observe state changes only for the urls in your filter.

import { fetchp, FetchpHookType } from "fetchp";

fetchp.hooks.addForUrl(
  FetchpHookType.StateChange,
  ["GET", "POST"],
  /^https:\/\/jsonplaceholder\.typicode\.com\//,
  (request, status) =>
    console.log(`[state change] ${request.url} -> ${status}`),
);

const response = fetchp.request(
  "GET",
  "https://jsonplaceholder.typicode.com/todos",
);

On-Demand Fetching

Assume that you don't want to invoke the request immediately. You'll set up an external trigger for this.

import { fetchp } from "fetchp";

const req = fetchp.request("GET", "/posts", { immediate: false });

setTimeout(() => req.exec(), 500);

console.log(await req.data);

Mocking an URL for Request

Assume that your API is not yet built on the backend, and you want to mock its behavior.

import { fetchp } from "fetchp";

const mockContent = { hello: "world" };
const mockResponse = (request) =>
  new Response(
    JSON.stringify(mockContent),
    {
      status: 200,
      statusText: "OK",
      headers: {
        "content-type": "application/json",
      },
    },
  );

fetchp.mocks.add(["GET", "POST"], "/hello", mockResponse);

// mocking is done, let's make a request to the mocked URL
const req = fetchp.request("GET", "/hello");

// it will return { hello: "world" }
console.log(await req.data);

Mocking for Testing (Buggy ATM)

Assume that you want to mock your code without dealing with a test framework and its interfaces / methods. All you need to do is importing fetchp/mock instead of fetchp module.

// just replace fetchp with fetchp/mock
import { fetchp } from "fetchp/mock";

const req = fetchp.request("GET", "/posts");

console.log(await req.data);

Using with React Hooks

import { useFetchp } from "fetchp";

const MyComponent = (props) => {
  const { data, isLoading, error } = useFetchp("GET", "/posts");

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return <div>{JSON.stringify(data)}</div>;
};

Using with React Hooks, mocking for testing

// just replace fetchp with fetchp/mock
import { useFetchp } from "fetchp/mock";

const MyComponent = (props) => {
  const { data, isLoading, error } = useFetchp("GET", "/posts");

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error.message}</div>;
  }

  return <div>{JSON.stringify(data)}</div>;
};

Using with React Hooks, manual fetching

import { useEffect } from "react";
import { useFetchp } from "fetchp";

const MyComponent = (props) => {
  const { data, status, isSuccess, doFetch } = useFetchp(
    "GET",
    "/posts",
    false,
  );

  useEffect(() => {
    // fetch data after 500 milliseconds have passed
    setTimeout(() => doFetch(), 500);
  }, []);

  if (!isSuccess) {
    return <div>Status: {status}...</div>;
  }

  return <div>{status}: {JSON.stringify(data)}</div>;
};

Using with Deno

import { fetchp } from "npm:fetchp";

const req = fetchp.request("GET", "https://www.google.com/");

console.log(await req.data);

Todo List

See GitHub Projects for more.

  • [ ] Clean cache storage
  • [ ] Fixing the bug in fetchp/mock module
  • [ ] Add advanced support for hooks / middlewares / interceptors
  • [ ] Protobuf support
  • [ ] Registering serializers / deserializers by content-type
  • [ ] Logging adapters
  • [ ] MAYBE: Reducers / Actions?
  • [ ] Mechanism for request retries

Requirements

  • node.js (https://nodejs.org/)
  • Deno (to run tests and contribution) (https://deno.land/)

License

Apache 2.0, for further details, please see LICENSE file

Contributing

See contributors.md

It is publicly open for any contribution. Bugfixes, new features and extra modules are welcome.

  • To contribute to code: Fork the repo, push your changes to your fork, and submit a pull request.
  • To report a bug: If something does not work, please report it using GitHub Issues.

To Support

Visit my GitHub Sponsors profile at github.com/sponsors/eserozvataf