DEV Community

Cover image for Creating a Reddit Clone Using React and GraphQL — 06
Rasika Gayan Gunarathna
Rasika Gayan Gunarathna

Posted on • Edited on • Originally published at rasikag.com

Creating a Reddit Clone Using React and GraphQL — 06

Now we are adding the GraphQL request when we are making API calls. To do this we are using URQL GraphQL Client. using below command to add the relevant packages to the web app.

yarn add urql graphql
Enter fullscreen mode Exit fullscreen mode

Then we are adding the provider and client in _app.tsx file.

// _app.tsx
// add the client
const client = createClient({ url: "http://localhost:4001/graphql" });

<Provider value={client}>// wrap all the components</Provider>;
Enter fullscreen mode Exit fullscreen mode

Then we are adding the register mutation on client-side(urql hook). Here we are coping the graphql query and add the variable to get the username and password from our graphql playground.

const REGISTER_MUT = `mutation Register($username: String!, $password: String!) {
  register(options:{username:$username,password: $password}){
    user{
      id,
      username
    }
    errors{
      field
      message
    }
  }
}`;
Enter fullscreen mode Exit fullscreen mode

Here once we add the mutation as bellow. The first variable in the below array regarding the information on this mutation. At this moment we don’t want it. So we can leave it there as an empty object of leaving a comma as below.

const [, register] = useMutation(REGISTER_MUT);
Enter fullscreen mode Exit fullscreen mode

The second variable is our function and we call it as register. Then we can use it inside the onSibmit function as below.

onSubmit = {(value) => {register(value)}}
Enter fullscreen mode Exit fullscreen mode

Because here value, map with our keys we don’t need to manually assign them. Unless we need to do as below.

register({ username: values.username, password: values.password });
Enter fullscreen mode Exit fullscreen mode

Now we are adding some options createClient method. So we are including the credentials. This will help to get the cookie when you register or login.

const client = createClient({
  url: "http://localhost:4001/graphql",
  fetchOptions: {
    credentials: "include",
  },
});
Enter fullscreen mode Exit fullscreen mode

Also in register method that we used in onSubmit function in register.tsxfile, we are going to return it because it is returning a Promise . Unless in the UI, the register button will spin forever.

If we try this now, we will get an CORS error. To fix that we are adding our web app origin to Apollo Server.

apolloServer.applyMiddleware({
  app,
  cors: {
    origin: "http://localhost:3000",
  },
});
Enter fullscreen mode Exit fullscreen mode

But this will only resolve on Apollo server CORS . So we can add cors to the server project and manage CORS globally in the express server. But, this is one way to do it. It depends on how do manage the CORS withing your application that only for GraphQL or full application.

Add below yarn packages to the server project.

yarn add cors
yarn add -D @types/cors
// cors type support
Enter fullscreen mode Exit fullscreen mode

Then set cors false in the ApolloServer. Add cors as middleware.

app.use(
  cors({
    origin: "http://localhost:3000",
    credentials: true,
  })
);

// change apollo server cors to false
apolloServer.applyMiddleware({ app, cors: false });
Enter fullscreen mode Exit fullscreen mode

Also, in your tsconfig.json add the below line to bypass the libCheck. Because most probably now you will get an error while building the server application codebase.

"skipLibCheck": true,
Enter fullscreen mode Exit fullscreen mode

Now we fixed the CORS error at this moment. After that, we are making some improvement to register method as below(make it async function) because register method returns a Promise.

// register.tsx
onSubmit={async (values) => {
  const response = await register(values)
}}

Enter fullscreen mode Exit fullscreen mode

Now the issue is the response ‘s type is any . So let’s change it. We are adding GraphQL Code Generator that to the web app project. It looks at our query and generates the TypeScript type and generates the urql hooks.

yarn add -D @graphql-codegen/cli

Enter fullscreen mode Exit fullscreen mode

Now we are going to initiate the query generator. For that, execute the below command and set up the config questions.

yarn graphql-codegen init
Enter fullscreen mode Exit fullscreen mode

After all, questions answered, it will create a codegen.yml . In there we change typescript-react-apollo that in plugging to typescript-urql and add the below package.

yarn add -D @graphql-codegen/typescript-urql
Enter fullscreen mode Exit fullscreen mode

Also, here is the selection for GraphQL Code Generator.


Welcome to GraphQL Code Generator!
Answer few questions and we will setup everything for you.

? What type of application are you building?
Application built with React
? Where is your schema?: (path or url) http:/
/localhost:4001/graphql
? Where are your operations and fragments?: s
rc/graphql/**/*.graphql
? Pick plugins: TypeScript (required by other
 typescript plugins), TypeScript Operations (
operations and fragments), TypeScript React A
pollo (typed components and HOCs)
? Where to write the output: src/generated/gr
aphql.tsx
? Do you want to generate an introspection fi
le? No
? How to name the config file? codegen.yml
? What script in package.json should run the
codegen? gen
Fetching latest versions of selected plugins..

Enter fullscreen mode Exit fullscreen mode

Now we add src/graphql/mutations/register.graphql file and move our mutation in there. After that run yarn gencommand. Once you generate the types you can open the graphql.tsx file. You will see it created useRegisterMutation hook for us.

So, in register.tsxfile change the useMutation method to useRegisterMutation method. All others are the same.

const [, register] = useRegisterMutation();
Enter fullscreen mode Exit fullscreen mode

Now, the response’s type will be RegisterMutation . Cool, right?

Also, check that in tsconfig.json strict property and change it to true.

TypeScript Tips:

if (response.data) this will throw an error if data is undefined.

if (response.data?) this will return undefined if data is undefined.

This is called Optional Chaining.

Now we are handling the errors here. Let’s create a utility for it. It will transform qraphql error object to formik error object.

Best Practise:

The reason that we use this we have a contract that graphql will return the separate error format and fomik has a separate error object format. Whenever we use an input field we can reuse this errorMap

Here is the errorMap utility.

export const toErrorMap = (errors: FieldError[]) => {
  const errorMap: Record<string, string> = {};

  // destructed the FieldError { field, message }

  errors.forEach(({ field, message }) => {
    errorMap[field] = message;
  });
  console.log(errorMap);

  return errorMap;
};
Enter fullscreen mode Exit fullscreen mode

Then we can use it in the onSubmit error handler and pass the graphql error object. Let’s try it and see the below result. Cool. It is working.

Alt Text

Now, let's add a user. Once we register a new user successfully it will set the cookie in the browser.

The codebase for this article that can find in here.

rasikag/reddit-clone-webapp

rasikag/reddit-clone-server

I will wrap-up this post from here. Soon I will publish the next part of this blog post.

If you have anything to ask regarding this please leave a comment here. Also, I wrote this according to my understanding. So if any point is wrong, don’t hesitate to correct me. I really appreciate you.

That’s for today friends. See you soon. Thank you.

References:

This article series based on the Ben Award - Fullstack React GraphQL TypeScript Tutorial. This is amazing tutorial and I highly recommend you to check that out.

Main image credit

Top comments (0)