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
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>;
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
}
}
}`;
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);
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)}}
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 });
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",
},
});
Also in register
method that we used in onSubmit
function in register.tsx
file, 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",
},
});
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
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 });
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,
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)
}}
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
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
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
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..
Now we add src/graphql/mutations/register.graphql
file and move our mutation in there. After that run yarn gen
command. Once you generate the types you can open the graphql.tsx
file. You will see it created useRegisterMutation
hook for us.
So, in register.tsx
file change the useMutation
method to useRegisterMutation
method. All others are the same.
const [, register] = useRegisterMutation();
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 returnundefined
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 andfomik
has a separate error object format. Whenever we use an input field we can reuse thiserrorMap
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;
};
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.
Show errors messages.
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.
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