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

@rigil/apifetch

v2.0.0

Published

library wrapping fetch for easier usage

Downloads

68

Readme

apifetch

An API focused simplified fetch.

Install

$ npm i @rigil/apifetch

Basic usage

import api from '@rigil/apifetch'

// with import we get a default instance of the API
// we can change a few properties (see options paragraph)
api.setBaseURL('http://myserver.api/v1')

// and make requests, JSON by default
let allUSers = await api.get('users')
let oneUser = await api.get('users', {
  email: '[email protected]'
})

// on POST requests the second argument is for the request body, the third
// the third will make aditional url parameters
let newUser = await api.post('users', {
  email: '[email protected]',
  password: 'secret'
})

await api.delete('users', { id: newUser.id })

Additional instances

But we can create new instances with specific options.

import { createApiInstance } from '@rigil/apifetch'

const codebergApi = createApiInstance({
    baseURL: 'https://codeberg.org/api/v1'
})

export codebergApi

Options

The apifetch object uses a set of options for each instance. You can set there any fetch options, plus a few ones that are specific to apifetch:

| Option | Default | Description | |--------|---------|-------------| | baseURL | '' | URL prefix for all requests | | autoJson | true | enables automatically converting data to JSON in requests and JSON to data in responses | | cacheTime | DEFAULT_TIMEOUT | enables cache feature using a timeout in milliseconds (0 will disable cache) | | beforeRequest | [] | see Interceptors | | afterResponse | [] | see Interceptors |

Methods

The first set of methods are to alter options after instance creation.

setBaseURL(baseURL)

It's the URL prefix used for all requests. Hence, the resource parameter in request calls can be relative to this prefix, and really represent a resource.

api.setBaseURL('https://codeberg.org/api/v1')

setAutoJson(enable)

If set, any request with a body, and if no Content-Type header has been specified, will have the body converted to a JSON string.

In the other way, all responses with a Content-Type matching /json/ will have their bodies converted to objects (or arrays)

If not enabled, the request requires a body as described by the fetch API and the response will be the bare body as returned by fetch.

setCacheTime(milliseconds)

For all GET requests, a cache is maintained to avoid fetching the same data too quickly over the network. This cache is enabled by default to 1 second, but can be adjusted this way, or disabled with a cache time of 0.

When data is cached for a specific URL, no network fetch is performed at all (unless a request interceptor is made to do it).

api.setCacheTime(0)

setAuthorization(token, type)

The Authorization header can be automatically set for all requests to manage... authorization. For this, you call this method with a token (or not to remove the authorization), and optionnaly a type which will be the header content prefix (defaults to Bearer).

// enable authorization if mytoken is not null
api.setAuthorization(myToken) // Authorization: Bearer {myToken}
// set authorization to API client ID
api.setAuthorization(clientID, 'ClientID') // Authorization: ClientID {clientID}
// remove authorization header from all requests
api.setAuthorization()
api.setAuthorization(false) // same, more explicit

Request methods

Unlike fetch you don't put query parameters in the URL directly (although you can if you want). The resource centric API style of apifetch separates the endpoint (base URL) from the resource denomination and its filtering through parameters.

The params parameter is an object containing query parameters (they all need to have a value, so myurl?isNotPossible is not available).

It's not possible either to mix query parameters in the resource and params parameters. apifetch is dumb and will try to insert two ? in the URL.

api.get(resource, params, additionalFetchOptions)
api.post(resource, body, params, additionalFetchOptions)
api.put(resource, body, params, additionalFetchOptions)
api.patch(resource, body, params, additionalFetchOptions)
api.delete(resource, params, additionalFetchOptions)
api.head(resource, params, additionalFetchOptions)

There is also a generic call where you can set your own method:

api.request(method, resource, params, body, additionalFetchOptions)

Interceptors

Interceptors permit to tweak requests and responses around fetch calls, through the beforeRequest and afterResponse options, which should be arrays of functions.

In beforeRequest each request function receives the final url and options passed to fetch and can either return:

  • a FetchParams object containing modified url and options in its input and init properties respectively
  • a Response object, in which case process is stopped and this response is returned to caller (hint: that's how mock can be implemented)
import { FetchParams, createApiInstance } from 'apifetch'

const api = createApiInstance({
  // ...
  beforeRequest: [
    // dummy request interceptor
    async (url, options) => new FetchParams(url, options),
    // shortcuting interceptor sending a response
    async (url, options) => new Response('{}', {
      status: 200,
      statusText: 'I faked it!',
    })
  ]
})

Likewise, after fetch returns its response, this one can be altered with afterResponse interceptors with the request's url and options, plus a copy of the latest response (from fetch or previous interceptor).

const api = createApiInstance({
  // ...
  afterResponse: [
    // dummy response interceptor
    async (url, options, response) => response
  ]
})

IMPORTANT

Interceptors must be inserted on the instance creation, or sent through requests options parameters. They can't be altered with methods.

But you can manage arrays yourself and modify them after giving them by reference, to get the same result.

const myRequestInterceptors = [
  async (url, options) => new FetchParams(url, options)
]

const api = createApiInstance({
  // ...
  beforeRequest: myRequestInterceptors
})

myRequestInterceptors.push(
  async (url, options) => new Response('{}', {
    status: 200,
    statusText: 'I faked it!',
  })
)