Comparison of the GraphQL Workflow with/without Chimp

Let's take a look at how using chimp can benefit your workflow when working on GraphQL Apollo Server.

Read through or watch the video here:

With chimp

First we will take a look at adding a new module with a query with Chimp.

We will be using repo with the default branch of data-sources-with-chimp

First let's create a new module with graphql file: ./src/Echo/Echo.graphql

type EchoResponse {
    text: String!
    length: Int! @computed

extend type Query {
    echo(text: String!): EchoResponse!

Take note that we use @computed directive to tell Chimp to generate a field level resolver for that field.

Now generate all the things (using chimp):

 npm run graphql:generateAll

You will see a few new files, in particular one with a resolver for the Query and one with the resolver for the EchoResponse.length field.

Let's take a look at the Query first:

import { QueryResolvers } from "@generated/graphql/types";

export const echoQuery: QueryResolvers["echo"] = (parent, args, context) => {
  throw new Error("not implemented yet");

And replace throwing an error with returning the object with text:

export const echoQuery: QueryResolvers["echo"] = (parent, args, context) => ({
  text: args.text

Now the field level resolver:

import { EchoResponseResolvers } from "@generated/graphql/types";

export const EchoResponseLength: EchoResponseResolvers["length"] = (
) => {
  throw new Error("Not implemented yet");

Let's replace the error with returning the length for the text that comes from the parent (in our case - the Echo Query)

import { EchoResponseResolvers } from "@generated/graphql/types";

export const EchoResponseLength: EchoResponseResolvers["length"] = (
) => parent.text.length;

And that's it! You can start the server (npm start) and check the query:

Without chimp

Now for the non-chimp part!

We will be using repo with the  data-sources branch.

Similarly to Chimp - let's create ./src/Echo/Echo.graphql

type EchoResponse {
  text: String!
  length: Int!

extend type Query {
  echo(text: String!): EchoResponse!

Now we have to manually create the resolvers file and implement it. I usually copy and paste a small resolvers file from a different module and modify it to the shape I need.

export const echoResolvers = {
  Query: {
    echo: (_, args) => {
      return { text: args.text };
  EchoResponse: {
    length: (echo) => {
      return echo.text.length;

Now we need to manually add it to the existing resolvers:

// (..)
import { echoResolvers } from "./Echo/echoResolvers";
export const resolvers = merge(

You can start the app and run the query, it should work exactly the same way.

So, what's the big deal? Both options seemed easy.

The difference is in the fact that doing things manually is error-prone, there is literally tens of ways you could make this not work on the non-chimp part, from not adding the resolvers (or not adding them correctly), to not implementing the resolvers properly. I had a dry run for recording a video for this article, and then the final one. In both cases I made an error in implementing the Echo Query resolver. Instead of returning {text: args.text} I just returned the args.text (as if the query should return a String, not EchoResponse - which is an object). The first time around I made that mistake in the non-chimp case and hit a runtime error when running the query. It took me a a few minutes to figure out what's wrong. The second time around I made that mistkae with the chimp watching my back - and the moment I made the error typescript shouted at me, that I'm returning a string instead of an object. In general - the sooner you get the feedback while coding, the less time it will take to fix a problem, and the more likely you are to stay in the flow (which is where happiness comes from ;-) )

Obviously you could have manually generated types based on your schema, and then manually attach them to your resolvers, but it's not really straightforward, people forget to do that, or do it incorrectly. It's also easy to get the shape of the resolvers correct, so you could have the types happy, but runtime again. You could also just forget to implement a field level resolver - with chimp, it's generated for you with a failing test, so it's tough to miss.

And speaking of tests - we generate the scaffolds for your tests. Here we didn't implement them to make the comparison more apples to apples, but they make testing super easy, which is definitely not the case when working with typical apollo server.

Let me know if you have any questions or thoughts in the comments below.

Let us help you on your journey to Quality Faster

We at specialize in helping our clients get more for less. We can get you to the holy grail of continuous deployment where every commit can go to production — and yes, even for large enterprises.

Feel free to schedule a call or send us a message below to see how we can help.

User icon
Envelope icon


Schedule a 30m call
  • Better way to use useReducer with TypeScript

    Introducing useComplexState hook, - a small wrapper combining Redux Toolkit, useReducer with some extra syntax sugar to make things even simpler and more to-the-point.

  • Dealing with randomness in tests

    A few patterns to help you deal with randomness in your codebase.

  • How to deal with the yarn link "There's already a package called x registered" error

    Short discussion about helpful error messages, and a solution to the problem