Skip to content
Use centralized models to manage derived UI data for GraphQL response.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

GraphQL Client Models npm version

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.

To watch an example with the react-apollo integration, go to the example on CodeSandbox

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.


yarn add graphql-client-models


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}!`

// => 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}`

// => My first name is Walter


createTransform(models, [options])


Type: object

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

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


Type: object


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: string

corresponding GraphQL type


Type: string

property name in transformation result

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

Type: function

The getter will be evaluated when the property is accessed


object of current type


object of current type without getters assigned


complete response data passed to transform


returned value of getContext


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.


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.



You can’t perform that action at this time.