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-client-models

v0.2.0

Published

Build models by GraphQL's type

Downloads

3

Readme

GraphQL Client Models

Use centralized models to manage derived UI data for GraphQL response.

  • Automatic Automatically transform GraphQL response by your model definitions regardless the response's structure.
  • Centralized Define model once and use anywhere in your code.
  • Lazy evalutaion Uses getter. Field won't be calculated until you need it.
  • Small It's a small library with zero dependency.

Why & How

In a client-side application, we need to deal with API response and transform it to fit our need of UI derived data. For GraphQL's response, it's trivial to transform nested & complicated data due to GraphQL's flexible nature.

Fortunately, GraphQL provides meta-fields __typename, so we're able to know the structure of GraphQL response. we can find the targeted object that we're going to transform based on GraphQL type whether it's nested inside another object or arrray.

graphql-client-models recursively check response's each object. if it finds an object with a __typename matching with any defined model, the model's getters will be set on the object, so we can access properties added by the model like it's original in the response.

Installation

yarn add graphql-client-models

Usage

import { createTransform } from 'graphql-client-models'

/* Define model and it's fields */
const models = {
  User: {
    fullName: self => `${self.firstName} ${self.lastName}`
  }
}
/* Create transform function */
const transform = createTransform(models)

/**
 * Response from GraphQL service
 * {
 *   user {
 *     firstName: 'Walter'
 *     lastName: 'White'
 *     followers: [
 *       {
 *         firstName: 'Jesse'
 *         lastName: 'Pinkman'
 *         __typename: 'User'
 *       }
 *     ]
 *     __typename: 'User'
 *   }
 * }
 */

/* Transform response data */
const result = transform(response)

console.log(result.user.fullName) //=> Walter White
console.log(result.user.followers[0].fullName) //=> Jesse Pinkman

The example uses apollo-client as the client because it adds __typename to each query automatically. If you are using different graphql client, you may need to add __typename manually.

You can also reuse model's getter.

const models = {
  User: {
    fullName: self => `${self.firstName} ${self.lastName}`,
    // Reuse 'fullName' to create 'sayHello'
    sayHello: self => `Hello! This is ${self.fullName}!`
  }
}

console.log(result.user.sayHello)
// => Hello! This is Walter White!

You're able override existing field in response but you have to use orginal of the second argument to prevent infinite loop.

const models = {
  User: {
    firstName: (_, { original }) =>
      `My first name is ${original.firstName}`
  }
}

console.log(result.user.firstName)
// => My first name is Walter

API

createTransform(models, [options])

models

Type: object

define getters for each type. See below for models structure.

returns transform function. You can use transform function in your server response.

options

Type: object

options.getContext

Type: function Default: () => {}

To pass in extra data which is not related the response data but useful in getter. The result of getContext will be passed to the getter which is been executing.

In practice, you can pass in Apollo client's instance to getContext, so you can use client.readFragment to read cached data from other requests.

const models = {
  SomeModel: {
    someField: (_, { context: { client }}) => {
      client.readFragment(/*...*/) // to read cached data
    }
  }
}

createTransform(models, { getContext: () => ({ client: apolloClient }) })

Model's structure

{
  <type>: {
    <field>: <getter>
  }
}

type

Type: string

corresponding GraphQL type

field

Type: string

property name in transformation result

getter(self, { original, root, context })

Type: function

The getter will be evaluated when the property is accessed

self

object of current type

original

object of current type without getters assigned

root

complete response data passed to transform

context

returned value of getContext

Future

I built this library because I heavily used Apollo GraphQL in my work. Thanks to Apollo. It saved me a lot of time dealing with GraphQL. I'd like to make it more convenient by building an apollo link for this library. By now, however, the response can not be modified in link (see: apollo-client#2534). I'll keep following the possibility to integrate it.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT