DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for I Migrated Away from Apollo Client to Vercel SWR and Prisma graphql-request...and You Can Too!
Aryan J
Aryan J

Posted on • Updated on • Originally published at thewebdevcoach.com

I Migrated Away from Apollo Client to Vercel SWR and Prisma graphql-request...and You Can Too!

GraphQL requests are simply POST requests made to your GraphQL endpoint. Why, oh why, does it need all this overhead of setting up an Apollo Client?

I was tired of setting up Apollo Client and it proved to be a huge headache when paired with Vercel Next.js's Now. Something needed to give.

Enter Prisma's graphql-request (for making the actual POST request) and Vercel SWR (for state caching). By remove Apollo Client, I manage to shave off 40 kB from my JavaScript build. I mean, look at this Next.js with Apollo hell I avoided!

OK, OK, you came here for examples of how to migrate. Here they are!

Basic Query without a Variable

With Apollo Client

// with Apollo Client:
import { gql, useQuery } from '@apollo/client';

const PAID_JOBS_QUERY = gql`
  query paidJobPosts {
    jobPosts {
      id
    }
  }
`;
const yourReactComponent = () => {
  const { data, loading, error } = useQuery(PAID_JOBS_QUERY); 
}

With Vercel SWR and Prisma graphql-request

// with SWR and graphql-request
import { request } from 'graphql-request';
import useSWR from 'swr';

// the comment below gives us VSCode syntax highlighting!
const PAID_JOBS_QUERY = /* GraphQL */ `
  query paidJobPosts {
    jobPosts {
      id
    }
  }
`;
const yourReactComponent = () => {
  const { data, error } = useSWR(PAID_JOBS_QUERY, (query) => request('/api', query));
  const loading = !data;
};

Basic Query with a Variable

With Apollo Client

// with Apollo Client:
import { gql, useQuery } from '@apollo/client';
const JOB_POST_BY_ID_QUERY = gql`
  query jobPostByIdQuery($id: String) {
    jobPost(where: { id: $id }) {
      id
    }
  }
`;
const yourReactComponent = ({ id }) => {
  const { data, loading, error } = useQuery(JOB_POST_BY_ID_QUERY, { variables: { id } });
};

With Vercel SWR and Prisma graphql-request

// with SWR and graphql-request
import { request } from 'graphql-request';
import useSWR from 'swr';

// the comment below gives us VSCode syntax highlighting!
const JOB_POST_BY_ID_QUERY = /* GraphQL */ `
  query jobPostByIdQuery($id: String) {
    jobPost(where: { id: $id }) {
      id
    }
  }
`;
const yourReactComponent = ({ id }) => {
  const { data, error } = useSWR([JOB_POST_BY_ID_QUERY, id], (query, id) => request('/api', query, { id }));
  const loading = !data;
};

Basic Mutation with Variables

With Apollo Client

// with Apollo Client:
import { gql, useMutation } from '@apollo/client';

const CREATE_JOB_POST_MUTATION = gql`
  mutation createJobPostMutation($jobName: String!) {
    createOneJobPost(jobName: $jobName) {
      id
    }
  }
`;
const yourReactComponent = () => {
  const [createJobPost] = useMutation(CREATE_JOB_POST_MUTATION);

  const submitJobPost = async (jobName) => {
    const { data } = await createJobPost({ variables: { jobName } });
    // do something with job post
  };
};

With Prisma graphql-request

// with SWR and graphql-request
import { request } from 'graphql-request';

const CREATE_JOB_POST_MUTATION = /* GraphQL */ `
  mutation createJobPostMutation($jobName: String!) {
    createOneJobPost(jobName: $jobName) {
      id
    }
  }
`;
const createJobPost = (variables) => {
  return request('/api', CREATE_JOB_POST_MUTATION, variables);
};

const yourReactComponent = ({ id }) => {
  const submitJobPost = async (jobName) => {
    const data = await createJobPost({ jobName });
    // do something with data
  };
};

Mutation with Cache Refreshing

With Apollo Client

// with Apollo Client:
import { gql, useMutation, useQuery } from '@apollo/client';

const ME_QUERY = gql`
  query MeQuery {
    me {
      id
    }
  }
`;
const someReactComponentThatFetchesMe = () => {
  const { data } = useQuery(ME_QUERY);
};

const SIGNIN_MUTATION = gql`
  mutation signInMutation($email: String!, password: String!) {
    signin(email: $email, password: $password) {
      id
    }
  }
`;
const yourReactComponent = () => {
  const [signin] = useMutation(SIGNIN_MUTATION);

  const submit = (email, password) => {
    signin({ variables: { email, password }, refetchQueries: [{ query: ME_QUERY }] });
  };
};

With Vercel SWR and Prisma graphql-request

// with SWR and graphql-request
import { request } from 'graphql-request';
import useSWR from 'swr';

const ME_QUERY = /* GraphQL */ `
  query MeQuery {
    me {
      id
    }
  }
`;
const someReactComponentThatFetchesMe = () => {
  const { data } = useSWR(ME_QUERY); // the key to this value in cache is the value fo ME_QUERY
};

const SIGNIN_MUTATION = /* GraphQL */ `
  mutation signInMutation($email: String!, password: String!) {
    signin(email: $email, password: $password) {
      id
    }
  }
`;
const signIn = (variables) => {
  return request('/api', SIGNIN_MUTATION, variables);
};

const yourReactComponent = () => {
  const { mutate } = useSWR(ME_QUERY); // the mutate function will do the refetching for us

  const submit = async (email, password) => {
    await signin({ email, password });
    mutate(); // call mutate here to refetch Me after signin
  };
};

Top comments (19)

Collapse
 
shinabr2 profile image
ShinaBR2

Hi, this article looks nice for me. The only reason for using Apollo Client of mine is "caching", nothing else.
I have used graphql-request for my recently cloud functions and I like it's small.
But I'm using Gatsby, with a lot of issue related to SSR. Have you success with Vercel SWR in Gatsby? And how about the caching strategy between Apollo Client and Vercel SWR?
For me, I just need very simple caching strategy and setup also.
Thanks for nice article again :D

Collapse
 
aryanjnyc profile image
Aryan J

Hey Shina!

SWR is the caching solution while graphql-request will take care of making the actual GraphQL requests.

I have no experience with using Vercel SWR in Gatsby but I have used it with Next.js (which also implements SSR).

Collapse
 
shinabr2 profile image
ShinaBR2

Okay thanks, let me deep dive into and see <3 keep moving on.

Collapse
 
tettoffensive profile image
Stuart Tett

Where did you find out about this syntax:

const JOB_POST_BY_ID_QUERY = /* GraphQL */ `
  query paidJobPosts {
    jobPosts {
      id
    }
  }
`;

The examples in the graphql-request repo look like your apollo client version:

const query = /* GraphQL */ `
    query getMovie($title: String!) {
      Movie(title: $title) {
        releaseDate
        actors {
          name
        }
      }
    }`
Collapse
 
aryanjnyc profile image
Aryan J

Hi Stuart! The two are the same (GraphQL syntax is the same no matter which client you use.

The getMovie example requires a parameter (title) which is why you see it written like that.

Is that what you were talking about?

Collapse
 
tettoffensive profile image
Stuart Tett

If that is the case, then I think there is a mistake in your code in the article, because they do not match. Or I'm not understanding, because I expected the two examples to be compare/contrast of the different clients.

Thread Thread
 
aryanjnyc profile image
Aryan J

You're 100% right! As a compare/contract article, I should keep the code consistent. Thank you for pointing that out!

Collapse
 
hongducphan profile image
Phan Hong Duc • Edited on

hi, I am learning Nextjs with Graphql.
I have a problem when using useSWR to fetch data from Graphql api.
const ALL_PRODUCTS2 = /* GraphQL */
query allProducts($skip: String!, $take: String!) {
allProducts(skip: $skip, take: $take) {
id
name
}
}
;`

const fetcher = (query: any, first: string, take: string) => request('localhost:3000/api/graphql', query, {first, take});

export default function Products() {
const {data} = useSWR([ALL_PRODUCTS2, '0', '3'], fetcher)
const loading: boolean = !data;
.......
}`

=> I get the error : ClientError: Variable "$skip" of required type "String!" was not provided.: {"response":{"errors":[{"message":"Variable \"$skip\" of required type \"String!\" was not provided.","locations":[{"line":2,"column":23}]}],"status":500},"request":{"query":"\n query allProducts($skip: String!, $take: String!) {\n allProducts(skip: $skip, take: $take) {\n id\n name\n }\n }\n","variables":{"first":"0","take":"3"}}}

Please help me to fix it. thank you!!!

I am trying migrate from apolo to swr, and follow your instruction but... With apolo, it works.

Thank you!

Collapse
 
naveen_bharathi_a55cc4187 profile image
Naveen Bharathi

Hi @hongducphan ,
You passed 'first' instead of 'skip' in the fetcher function. That is the problem. Renaming it should fix the issue.

query allProducts($skip: String!, $take: String!) {
                   Μ… Μ… Μ… Μ… Μ… 
  allProducts(skip: $skip, take: $take) {
    id
    name
  }
}
Enter fullscreen mode Exit fullscreen mode
const fetcher = (query: any, first: string, take: string) => request('localhost:3000/api/graphql', query, { first, take });
                                                                                                             Μ… Μ… Μ… Μ… Μ…
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dberhane profile image
Daniel Berhane • Edited on

Hi Aryan, excellent work. I am considering switching from Apollo to graphql-request as well. But graphql-request does not seem to have pagination support for relay style cursor. Do you have any idea on how to enable pagination for the above solution you are proposing?

Collapse
 
oxcid profile image
oxcid

Hey Aryan, thanks for the article! Quick question, for authentication, what's your recommended way of doing it? Do we have to use graphql-request? Or any other way of doing it? Does SWR have authentication?

Collapse
 
aryanjnyc profile image
Aryan J

Hey! This is the first I've heard of it. Looks right up my alley. I'll try it in a future project!

Collapse
 
mikevb3 profile image
Miguel Villarreal

Thanks Aryan!! your post was very helpful!! i can believe how helpful swr & graphql-request are!

Collapse
 
lodisy profile image
Michael

Any way to implement GraphQL with useSWRInfinite?

Collapse
 
matepaiva profile image
Matheus Paiva

Hello, Aryan. Great article, congratz! Do you make your server-side requests using SWR as well, or did you migrate only the client-side requests?

Collapse
 
aryanjnyc profile image
Aryan J • Edited on

I make all GraphQL requests using graphql-request. SWR is only for caching (and only for the React client).

Collapse
 
svirins profile image
Dzmitry Sviryn

I followed the same path (Apollo => SWR + graphql-request). It fits perfectly into my workflow. Also, it seems to be slightly quicker than Apollo.
Thank you for your article, Aryan.

Collapse
 
svirins profile image
Dzmitry Sviryn

also, let me suggest:
const loading = !error && !data

We're hiring!

We're Hiring

We're looking for a Senior Full Stack Engineer to join the DEV team.

Head here to learn more.