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

@xavdid/json-requests

v0.3.0

Published

An extremely simple package for GETting and POSTing JSON.

Downloads

4

Readme

json-requests

This is a simple, modern, ergonomic, zero-dependency, JSON-only HTTP request client.

The package is intentionally light on features and configuration. Responses (and outgoing bodies, if applicable) must be JSON - if you need a different response type, use a different package.

It will soon have no external runtime dependencies. At time of writing, it wraps node-fetch, but once fetch is natively available in Node.js, that dependency will be removed.

Installation

The package is available on npm; install it via your favorite package manager:

yarn add @xavdid/json-requests

Usage

Usage is intentionally simple. Each method takes a url to start and Options to end. The postJSON method also takes a body in middle.

Each method returns a Promise that resolves to the JSON response from the server. Each method will also throw an error if the response status is >= 400 or the response isn't valid JSON. See error handling) for more info.

getJSON

function getJSON(url: string, options?: Options): Promise<Response extends object>

Examples

import { getJSON } from '@xavdid/json-requests'

// within an async function

// you can give the response shape in the function call
type Todo = {
  userId: number
  id: number
  title: string
  completed: boolean
}
const todo = await getJSON<Todo>('https://jsonplaceholder.typicode.com/todos/1')

// `todo` is correctly typed
console.log(todo.title) // "some title"

postJSON

function postJSON(
    url: string,
    body: object | undefined,
    options?: Options
): Promise<Response extends object>

Examples

import { postJSON } from '@xavdid/json-requests'

type Todo = {
  userId: number
  id: number
  title: string
  completed: boolean
}

// within an async function

// you can give the response shape in the function call
const updatedTodo = await postJSON<Todo>(
  'https://jsonplaceholder.typicode.com/posts',
  {
    title: 'foo',
    body: 'bar',
    userId: 1,
  }
)
// `updatedTodo` is correctly typed
console.log(updatedTodo.title) // "foo"

Options

The Options object takes two optional keys:

interface Options {
  // these can only be strings (headers object casts accordingly)
  headers?: { [k: string]: string }
  // there might be more types here
  query?: { [k: string]: string | number | boolean }
}

The accept and content-type headers are set automatically (and irrevocably).

These types intended to cover basic use; let me know if there's a common case that the types complain about.

// in an async function

// put query params in the object, not the url
const data = await getJSON('https://jsonplaceholder.typicode.com/todos', {
  query: { _limit: 10 },
})
// `data` has length 10

// pass auth as normal
const withAuth = await getJSON('https://httpbin.org/get', {
  headers: {
    authorization: 'Basic eGF2ZGlkOmh1bnRlcjI=',
  },
})

Examples

Error Handling

This package raises a custom error class, the ResponseError. It's thrown in 2 cases:

  1. The response content isn't valid JSON
  2. The server returns a status code >= 400

The error object has the following properties:

  • message: a human-readable description of the problem
  • code: a reliable string which pinpoints the issue. Useful for narrowing down the problem programmatically (much like Node.js error codes). Possible values are:
    • JSON_PARSE_ERROR
    • HTTP_ERROR
  • statusCode: the numeric HTTP response code
  • body: the response's body content. If the response was valid JSON, it'll be parsed. If not (code is JSON_PARSE_ERROR), it's a string. There are helper functions to help type this for you (see below)

Any other errors will be thrown normally.

Narrowing Functions

The package includes helper functions to improve the typing of thrown errors:

  • isJSONError(e): boolean: narrows to a single possible error type
  • isHTTPError(e): boolean: narrows to a single possible error type
  • isResponseError(e): boolean will let you know an error is any of the above (as opposed to a native or fetch-based error). Useful for safely accessing .statusCode or treating unknown errors differently

Examples

import { getJSON, isJSONError, isHTTPError } from '@xavdid/json-requests'

// within an async function

try {
  await getJSON('https://httpbin.org/xml')
} catch (e) {
  if (isJSONError(e)) {
    e.body // <-- string; response that's not parsable JSON, like "<xml>...</xml>"
  }
  if (isHTTPError(e)) {
    e.body // <-- object; parsed error response, like {error: "unable to X"}
  }

  if (isResponseError(e)) {
    // can be either of the above, but not a native error
    e.message // string; human readable message
    e.statusCode // number
    e.code // string; one of the above
  }
}