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

graphql-unwrap

v1.0.1

Published

Unwrap nested objects from GraphQL responses. Works with Hygraph and other providers.

Downloads

6

Readme

graphql-unwrap

Unwrap nested objects from GraphQL responses into a flat storage by ID. Works with Hygraph and other providers. Can be used either client-side or server-side.

GraphQL endpoints typically return nested data. Deep nesting and recursion can sometimes be hard to handle, though. This library turns every GraphQL response into a more manageable, flat data structure that makes client-side development easier.

Demo on Observable and Hygraph: observablehq.com

Setup

Install dependency from npm:

npm install graphql-unwrap

Import in your JavaScript code:

import unwrap from 'graphql-unwrap'

Requirements

For this client-side library to work, your GraphQL API must be able to return a globally unique ID and a type name for each entry. You must request these fields (id and __typename by default) in every query.

Usage

Quick start

unwrap(data, [options])

import { request } from 'graphql-request'
import unwrap from 'graphql-unwrap'

// `data` must include `id` and `__typename` for every entry
const data = await request('https://graphql.api.com/', query)

[entriesById, idsByEndpoint] = unwrap(data)

You can choose to unwrap only some of the endpoints in your query:

[entriesById, idsByEndpoint] = unwrap(data, ['posts', 'users'])

Or dig through multiple layers to get the items:

[entriesById, idsByEndpoint] = unwrap({
  updateBlogPosts {
    returning: [
      { /* ... */ }
    ]
  }
}, {
  queryPath: 'returning'
})

To override all defaults:

[entriesById, idsByEndpoint] = unwrap(data, {
  keys: ['posts', 'users'],
  queryPath: 'returning', // defaults to null
  itemsPath: 'items', // defaults to null
  idKey: 'uuid',
  typeKey: 'type'
})

unwrapOne(data, [options])

You can unwrap a single object or a list, which is handy when you have arbitrary GraphQL responses:

import { request } from 'graphql-request'
import { unwrapOne } from 'graphql-unwrap'

const data = await request('https://graphql.api.com/', `{
  insert_todos (
    objects: [{
      title: "Foo bar"
    }]
  ) {
    returning {
      __typename
      id
      title

      created_by {
        __typename
        id
        email
      }
    }
  }
}`)

[entriesById, ids] = unwrapOne(data.insert_todos.returning)

Deeply nested data

Let's think of the following example:

import { request } from 'graphql-request'
import unwrap from 'graphql-unwrap'

const data = await request('https://graphql.api.com/', `
  blogPosts (first: 20, orderBy: { field: created_at }) {
    __typename
    id
    title
    created_at

    authors {
      __typename
      id
      email

      country {
        __typename
        id
        name

        capital {
          __typename
          id
          name
        }
      }
    }
  }
`)

const [entriesById, blogPostIds] = unwrap(data, true)

We requested data nested on 4 levels. Once unwrapped, entriesById will include every unique resource only once, even though the GraphQL data might include the same author, country and capital multiple times. entriesById will also include all capitals and countries by their ID, even though they're nested in the original data.

As we requested the 20 most recent posts, blogPostIds will have their IDs in correct order. In nested reference fields, the order will also be correct - just IDs instead of recursive data.

Combining unwrapped data

In a typical application, you will make many queries that includes the same data. For example, when navigating from a blog post listing page into an actual blog post, some of the blog post data has already been loaded, while some is still missing.

The way to deal with this is to recursively merge new entries into the entries of previous responses, maintaining a single source of truth of the latest data that the API has sent.

This way, it's easy to render the title of the blog post, even if the body text is still being loaded, for example.

import { request } from 'graphql-request'
import unwrap from 'graphql-unwrap'
import merge from 'lodash-es/merge'

// This could be your Vuex store or other global state, or reusable in some other way
const allEntriesById = {}

function get (query) {

  // Request data
  [entriesById, ids] = unwrap(
    await request('https://graphql.api.com/', query)
  )

  // Update store
  merge(allEntriesById, entriesById)

  // Return the IDs the response included in order
  return ids
}

const blogPostIds = await get(blogQuery)

Options reference

Different GraphQL APIs have slightly different query and response formats. graphql-unwrap can help you parse the responses, if you set the correct options.

|Provider|queryPath (queries)|queryPath(mutations)|itemsPath (queries)|itemsPath (mutations)|richTextReferencesPath (mutations)| |-|-|-|-|-|-| |Hygraph| – | – | – | – | – | |Nhost| – | 'returning' | – | – | – | |8base| 'items' | 'items' | 'items' | 'items' | |