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

@beyonk/sapper-httpclient

v11.1.3

Published

An isomorphic http client for Sapper

Downloads

240

Readme

Sapper HttpClient

js-standard-style publish

Sapper isomorphic fetch library

Why

In sapper, there are three different ways of fetching data:

  • client
  • server
  • isomorphic (client + server)
  • retries (on various network errors)

This library helps you abstract over where you are fetching data, meaning that your code maintains consistency without having to worry about where your data is being fetched.

The way it does this is by trying to use the first available fetch method, and failing over to alternatives if a method is not available. The methods it tries are, in the following order:

  1. Any fetch library you pass to create() (for example, preload's this.fetch)
  2. window.fetch if the library detects it is running clientside
  3. node-fetch, or whatever you want to pass in, if nothing else is available (pure server-side)

Generally this means that your usage is the same no matter where you call it, with one exception - using this library in the preload method requires you to pass in Sapper's special this.fetch method, as it is not available outside of the preload method. Examples of which are below.

Usage

To use within a Sapper application:

Install it

npm i -D @beyonk/sapper-httpclient

Configure it (both server-side and client-side as there are two bundles)

// src/client.js && src/server.js
import Api from '@beyonk/sapper-httpclient'

Api.configure({ baseUrl: 'https://example.com/your/api/base' })

Use it on the client:

// src/routes/some-route.html
import { create } from '@beyonk/sapper-httpclient'

// in a method (client-side)
const api = create()
const json = await api.endpoint('some/endpoint').get()
console.log(json)

// in preload (isomorphic)
const api = create()
const json = await api
  .context(this) // Pass in "this" from preload, to sapper's built in "fetch" method, as well as providing this.redirect to handlers
  .endpoint('some/endpoint')
  .get()
console.log(json)

Use it on the server:

// src/routes/some-route.js
import fetch from 'node-fetch' // or Sapper's built in fetch
import { create } from '@beyonk/sapper-httpclient'

const api = create()
const json = await api
  .context({ fetch }) // pass node fetch in here.
  .endpoint('some/endpoint')
  .get()
console.log(json)

Handling the response

import { create } from '@beyonk/sapper-httpclient'

const api = create()
const json = await api
  .endpoint('some/endpoint')
  .get((json, httpStatus) => {
    console.log('json response is', json)
    console.log('http status code is', httpStatus)
  })

Methods

const api = create()
const client = api
  .endpoint('some/endpoint')

console.log(await client.get()) // Get endpoint
console.log(await client.payload({ foo: 'bar' }).put()) // Put with body
console.log(await client.payload({ foo: 'bar' }).post()) // Post with body
console.log(await client.query({ foo: 'bar' }).get()) // Get with query
console.log(await client.del()) // Delete
console.log(await client.headers({ foo: 'bar' }).put()) // Put with headers

client.query

The query method accepts an object of params as either a String or Array of Strings. If any property passed into the query is undefined it will be ignored.

const api = create()
const client = api
  .endpoint('some/endpoint')

console.log(await client.query({ foo: 'bar' }).get()) // will make a GET request to 'some/endpoint?foo=bar'
console.log(await client.query({ foo: 'bar', baz: 'qux' }).get()) // will make a GET request to 'some/endpoint?foo=bar&baz=qux
console.log(await client.query({ foo: ['bar', 'qux' ] }).get()) // will make a GET request to 'some/endpoint?foo=bar&foo=qux
console.log(await client.query({ foo: undefined, baz: 'qux' }).get()) // will make a GET request to 'some/endpoint?baz=qux

Using built in response handling

const api = create()
const profile = await api
  .endpoint('some/endpoint')
  .get(json => {
    return json.profile
  })
console.log(profile)

Catching errors

Per request

If no local error handler is specified, the fallback handler default is called. If this isn't specified, the error is logged to the console.

  await client
    .endpoint('some/url')
    .forbidden(e => {
      console.error('Forbidden', e)
    })
    .gone(e => {
      console.error('Gone', e)
    })
    .notFound(e => {
      console.error('Not found', e)
    })
    .accessDenied(e => {
      console.error('Access denied', e)
    })
    .conflict(e => {
      console.error('Conflict', e)
    })
    .paymentRequired(e => {
      console.error('Payment Required', e)
    })
    .preconditionFailed(e => {
      console.error('Precondition failed', e)
    })
    .badData(e => {
      console.error('Bad data', e)
    })
    .default(e => {
      // Any other error caught here
      console.error('Some error', e)
    })
    .get()

Handler signature

Handlers have a signature with two items:

.badData((e, ctx) => {
  console.error('Bad data', e)
  ctx.redirect('/foo/bar')
  // or
  ctx.error('/foo/bar')
})

ctx can be whatever you want really - it is whatever you pass in as context(...).

However, if the context object you pass in has a fetch function, this is used as the fetch for XHR requests, so that in sapper you can just pass the entire this object in preload:

export async function preload () {
  await Api
    .context(this) // fetch, redirect, error.
    .endpoint('foo/bar')
    ...
}

you can also pass in other things to the context:

export async function preload () {
  await Api
    .context({ ...this, baz: 'qux' })
    .endpoint('foo/bar')
    ...
}

At a global level

Request local error handlers override global error handlers, but if a local error handler are not specified, these will be called instead, if it exists.

Names are the same as the local handlers:

  import Api from '@beyonk/sapper-httpclient'
  import { goto } from '@sapper/app'

  Api.configure({
    baseUrl: 'https://example.com/your/api/base',
    handlers: {
      paymentRequired(e => {
        goto('/checkout')
      })
    }
  })

  await client
    .endpoint('some/url')
    .get()

Retries

The http client can retry if a network error is encountered. The default is retry: false, and requests won't be retried.

Configure it as follows:

import Api from '@beyonk/sapper-httpclient'

Api.configure({
  retry: {
    attempts: 3 // How many times to retry before giving up
    errors: [ 'ECONNRESET' ] // A list of error codes
  }
})

errors is an array of any number of the nodejs network error codes

Parsing error payloads

As of v7.0.0 the library defaults to parsing error payloads as JSON. This means you can use the data returned in your response.

  /** endpoint returns 401 with:
    {
      username: 'Naughty User'
    }
  **/

  await client
    .endpoint('some/url')
    .accessDenied(e => {
      console.error('You are not allowed', e.body.username)
    })

To turn this behaviour off, pass the option parseErrors with value false:

import Api from '@beyonk/sapper-httpclient'

Api.configure({
  parseErrors: false
})

Running Tests

npm test

Credits