Overfetching?

I have a bird for that!

Overfetching?

Someone fetches too much data.

REST

Almost

everyone.

GraphQL

?

Example

a.k.a. Story Time

Schema

type Post {
 _id: ID!
 views: Int!
}

type User {
 _id: ID!
 name: String!
 posts: [Post!]!
 totalViews: Int!
}

type Query {
 users: [User!]!
}

User.totalViews

is a sum of

Post.views

Resolvers

export const Query = {
 users: async () =>
  await getUsers()
};

export const User = {
 posts: async ({ _id }) =>
  await getPostsOf(_id),
 totalViews: async ({ _id }) =>
  sumViews(await getPostsOf(_id))
};

Will it scale?

Resolvers v2

export const Query = {
 users: async () =>
  await getUsersWithTotalViews()
};

export const User = {
 posts: async ({ _id }) =>
  await getPostsOf(_id)
};

Will it scale?

query {
  users {
    _id
  }
}

Resolvers are
overfetching!

Resolvers v3

export const Query = {
 users: async (_, _, _, info) =>
  includes(info, 'totalViews')
   ? await getUsersWithTotalViews()
   : await getUsers()
};

export const User = {
 posts: async ({ _id }) =>
  await getPostsOf(_id)
};

Will it scale?

Schema v2

type Post {
 _id: ID!
 likes: Int!
 reach: Int!
 views: Int!
}

type User {
 _id: ID!
 name: String!
 posts: [Post!]!
 totalLikes: Int!
 totalReach: Int!
 totalViews: Int!
}

type Query {
 users: [User!]!
}

User.total*

is a sum of

Post.*

Resolvers v4

export const Query = {
 users: async (_, _, _, info) =>
  includes(info, 'totalLikes')
   ? includes(info, 'totalReach')
    ? includes(info, 'totalViews')
     ? await getUsersWithLRV()
     : await getUsersWithLR()
    : includes(info, 'totalViews')
     ? await getUsersWithLV()
     : await getUsersWithL()
   : includes(info, 'totalReach')
    ? includes(info, 'totalViews')
     ? await getUsersWithRV()
     : await getUsersWithR()
    : includes(info, 'totalViews')
     ? await getUsersWithV()
     : await getUsers()
};

Will it scale?

DB

Code

Example

a.k.a. Story Time

AGAIN

Resolvers v5

import { astToOptions, astToPipeline }
 from 'sparrowql-graphql';

const prepareOptions = () =>
 // Use astToOptions!
 // See docs!

export const Query = {
 users: async (_, _, _, info) => {
  const pipeline = astToPipeline(
   info,
   prepareOptions()
  );

  return await Users
   .aggregate(pipeline)
   .toArray();
 }
};

Will it scale?

DB

Code

FAQ

FAA

  • Only MongoDB.

  • Your DB schema has to be a DAG.

  • There's a detailed Medium article.

  • In production since April 2018.

That's all!

Overfetching? I have a bird for that!

By Radosław Miernik

Overfetching? I have a bird for that!

GraphQL Wroclaw #4

  • 1,147