{"id":4739,"date":"2022-07-13T19:45:10","date_gmt":"2022-07-13T19:45:10","guid":{"rendered":"https:\/\/codevoweb.com\/?p=4739"},"modified":"2023-05-05T20:31:18","modified_gmt":"2023-05-05T20:31:18","slug":"nextjs-graphql-codegen-react-query-jwt-authentication","status":"publish","type":"post","link":"https:\/\/codevoweb.com\/nextjs-graphql-codegen-react-query-jwt-authentication\/","title":{"rendered":"Next.js, GraphQL-CodeGen, &#038; React Query: JWT Authentication"},"content":{"rendered":"\n<p><a href=\"https:\/\/www.graphql-code-generator.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">GraphQL Code Generator<\/a> is a plugin-based toolkit for automating and generating full-typed GraphQL operations. This article will teach you how to add access and refresh token functionalities to your Next.js app using React Query, <code><a href=\"https:\/\/www.npmjs.com\/package\/graphql-request\" target=\"_blank\" rel=\"noreferrer noopener\">graphql-request<\/a><\/code>, GraphQL CodeGen, React-Hook-Form,  and Zod.<\/p>\n\n\n\n<p>Next.js, React Query, and GraphQL Series:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"\/graphql-api-next-mongodb-access-and-refresh-tokens\">GraphQL API with Next.js &amp; MongoDB: Access &amp; Refresh Tokens<\/a><\/li>\n\n\n\n<li><a href=\"\/graphql-crud-api-nextjs-mongodb-typegraphql\">GraphQL CRUD API with Next.js, MongoDB, and TypeGraphQL<\/a><\/li>\n\n\n\n<li><a href=\"\/nextjs-graphql-codegen-react-query-jwt-authentication\">Next.js, GraphQL-CodeGen, &amp; React Query: JWT Authentication<\/a><\/li>\n\n\n\n<li><a href=\"\/nextjs-full-stack-app-with-react-query-and-graphql-codegen\">Next.js Full-Stack App with React Query, and GraphQL-CodeGen<\/a><\/li>\n<\/ol>\n\n\n\n<p>More practice:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/react-query-graphql-codegen-access-and-refresh-tokens\">React Query, &amp; GraphQL-CodeGen: Access, and Refresh Tokens<\/a><\/li>\n\n\n\n<li><a href=\"\/react-material-ui-and-react-hook-form-html-forms\">React, Material UI and React Hook Form: Login and Signup Forms<\/a><\/li>\n\n\n\n<li><a href=\"\/react-rtk-query-react-hook-form-and-material-ui-multipart-formdata\">React, RTK Query, React Hook Form and Material UI &#8211; Image Upload<\/a><\/li>\n\n\n\n<li><a href=\"\/react-redux-toolkit-jwt-authentication-and-authorization\">React + Redux Toolkit: JWT Authentication and Authorization<\/a><\/li>\n\n\n\n<li><a href=\"\/react-redux-toolkit-refresh-token-authentication\">React.js + Redux Toolkit: Refresh Tokens Authentication<\/a><\/li>\n\n\n\n<li><a href=\"\/vue-query-and-axios-crud-app\">Build Vue.js, Vue Query, and Axios CRUD App with RESTful API<\/a><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"850\" height=\"478\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication.webp\" alt=\"Next.js, GraphQL-CodeGen, &amp; React Query JWT Authentication\" class=\"wp-image-4815\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication.webp 850w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication-300x169.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication-768x432.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication-100x56.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Next.js-GraphQL-CodeGen-React-Query-JWT-Authentication-700x394.webp 700w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/figure>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-content-wrap{padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-contents-title-wrap{color:#ffffff;}.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-contents-title{color:#ffffff;font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-content-wrap .kb-table-of-content-list{color:#ffffff;font-weight:regular;font-style:normal;margin-top:10px;margin-right:0px;margin-bottom:0px;margin-left:-5px;}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}@media all and (max-width: 767px){.kb-table-of-content-nav.kb-table-of-content-id_d66fdc-16 .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}<\/style>\n\n\n<h2 class=\"wp-block-heading\">Next.js, React Query &amp; GraphQL-CodeGen Overview<\/h2>\n\n\n\n<span id=\"ezoic-pub-video-placeholder-107\"><\/span>\n\n\n\n<p>The user clicks on the &#8220;<strong>SignUp<\/strong>&#8221; link from the navigation menu to register for an account.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"947\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-947x1024.png\" alt=\"nextjs fullstack app react query graphql-codegen homepage\" class=\"wp-image-4745\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-947x1024.png 947w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-278x300.png 278w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-768x830.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-93x100.png 93w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage-416x450.png 416w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-homepage.png 999w\" sizes=\"auto, (max-width: 947px) 100vw, 947px\" \/><\/figure>\n\n\n\n<p>On the signup page, the user is required to provide the necessary credentials to create a new account.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"947\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-947x1024.png\" alt=\"nextjs fullstack app react query graphql-codegen register user\" class=\"wp-image-4743\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-947x1024.png 947w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-278x300.png 278w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-768x830.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-93x100.png 93w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user-416x450.png 416w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-register-user.png 999w\" sizes=\"auto, (max-width: 947px) 100vw, 947px\" \/><\/figure>\n\n\n\n<p>After the GraphQL server has successfully added the user to the database, React redirects the user to the login page.<\/p>\n\n\n\n<p>Next, the user makes a GraphQL request with React Query and <code><a href=\"https:\/\/www.npmjs.com\/package\/graphql-request\" target=\"_blank\" rel=\"noreferrer noopener\">graphql-request<\/a><\/code> to the Next.js GraphQL server in order to sign in.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"948\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-948x1024.png\" alt=\"nextjs fullstack app react query graphql-codegen signin user\" class=\"wp-image-4742\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-948x1024.png 948w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-278x300.png 278w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-768x829.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-93x100.png 93w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user-417x450.png 417w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-signin-user.png 1000w\" sizes=\"auto, (max-width: 948px) 100vw, 948px\" \/><\/figure>\n\n\n\n<p>After the user has been authenticated by the Next.js GraphQL server, Next.js redirects the user to the profile page where his credentials are displayed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"946\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-946x1024.png\" alt=\"nextjs fullstack app react query graphql-codegen profile page\" class=\"wp-image-4744\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-946x1024.png 946w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-277x300.png 277w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-768x831.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-92x100.png 92w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page-416x450.png 416w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/nextjs-fullstack-app-react-query-graphql-codegen-profile-page.png 998w\" sizes=\"auto, (max-width: 946px) 100vw, 946px\" \/><\/figure>\n\n\n\n<p>To see the cookies returned by the Next.js GraphQL server, open the dev tools then click on the &#8220;<strong>Application<\/strong>&#8221; tab and select &#8220;<strong>Cookies<\/strong>&#8221; from the storage section.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"1013\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser.png\" alt=\"jwt refresh access token cookies in the browser\" class=\"wp-image-1472\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser.png 975w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser-289x300.png 289w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser-768x798.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser-433x450.png 433w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/05\/jwt-refresh-access-token-cookies-in-the-browser-600x623.png 600w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Setup React Query &amp; GraphQL CodeGen in Next.js<\/h2>\n\n\n\n<p>GraphQL Code Generator supports popular clients (React Query, React Apollo Client, URQL, and other clients) and provides specific plugins to be used in conjunction with each target client.<\/p>\n\n\n\n<p>You can find the plugins and configuration options available for each target client from the following guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.graphql-code-generator.com\/docs\/guides\/react#react-query\" target=\"_blank\" rel=\"noreferrer noopener\">React Query<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.graphql-code-generator.com\/docs\/guides\/react#apollo-and-urql\" target=\"_blank\" rel=\"noreferrer noopener\">Apollo and URQL<\/a><\/li>\n<\/ul>\n\n\n\n<p>However, we will focus on GraphQL CodeGen with React Query, the available plugins, and configuration options.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Install and Setup React Query<\/h3>\n\n\n\n<p>With that out of the way, run this command to install <a href=\"https:\/\/react-query.tanstack.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">React Query<\/a>:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add react-query\n# or\nnpm install react-query\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong> <a href=\"https:\/\/react-query.tanstack.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">React Query<\/a> is compatible with React <strong>v16.8+<\/strong> and works well with <strong>ReactDOM<\/strong> and <strong>React Native<\/strong>.<\/p>\n<\/blockquote>\n\n\n\n<p>In this section, we will add Next.js support for server-side rendering and React Query prefetching.<\/p>\n\n\n\n<p>There are two ways we can handle React Query prefetching for our server-side rendered pages:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We can prefetch the data ourselves and pass it to the <code>useQuery()<\/code> hook as <code>initialData<\/code> . This strategy is simple and requires minimal setup but it has some caveats.<\/li>\n\n\n\n<li>The second approach is to prefetch the query on the server, dehydrate the cache and rehydrate it on the client.<\/li>\n<\/ol>\n\n\n\n<p>To set up server-side query caching and hydration with Next.js and React Query, we need to create the <code><a href=\"https:\/\/react-query.tanstack.com\/reference\/QueryClient\" target=\"_blank\" rel=\"noreferrer noopener\">QueryClient<\/a><\/code> instance and pass it to the <code><a href=\"https:\/\/react-query.tanstack.com\/reference\/QueryClientProvider\" target=\"_blank\" rel=\"noreferrer noopener\">&lt;QueryClientProvider&gt;<\/a><\/code> component. <\/p>\n\n\n\n<p>Next, let&#8217;s wrap the app component with the <code>&lt;Hydrate&gt;<\/code> component and provide it with a <code>dehydratedState<\/code> prop from <code>pageProps<\/code> .<\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport '..\/styles\/globals.css';\nimport type { AppProps } from 'next\/app';\nimport { QueryClientProvider, Hydrate, QueryClient } from 'react-query';\nimport { ReactQueryDevtools } from 'react-query\/devtools';\nimport React from 'react';\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  const [queryClient] = React.useState(() =&gt; new QueryClient());\n  return (\n      &lt;QueryClientProvider client={queryClient}&gt;\n        &lt;Hydrate state={pageProps.dehydratedState}&gt;\n            &lt;Component {...pageProps} \/&gt;\n          &lt;ReactQueryDevtools initialIsOpen={false} \/&gt;\n        &lt;\/Hydrate&gt;\n      &lt;\/QueryClientProvider&gt;\n  );\n}\n\nexport default MyApp;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Install GraphQL and GraphQL-Request<\/h3>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add graphql graphql-request\n# or\nnpm install graphql graphql-request\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/graphql-request\" target=\"_blank\" rel=\"noreferrer noopener\">graphql-request<\/a><\/code> &#8211; is a minimalist GraphQL client similar to Axios but designed specifically for making GraphQL requests.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/graphql\" target=\"_blank\" rel=\"noreferrer noopener\">graphql<\/a><\/code> &#8211; a query language and runtime which can be used in a Node.js server and the browser.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">GraphQL-CodeGen Manual Setup<\/h3>\n\n\n\n<p><a href=\"https:\/\/www.graphql-code-generator.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">GraphQL-CodeGen<\/a> is a tool designed to automate the generation of typed queries, mutations, and subscriptions for React, Next.js, Vue, Angular, Svelte, and other frontend frameworks.<\/p>\n\n\n\n<p>Now open your terminal and run this command to install the GraphQL Code Generator CLI tool to help us generate the GraphQL React Query hooks.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add -D graphql @graphql-codegen\/cli\n# or \nnpm install -D graphql @graphql-codegen\/cli\n<\/code><\/pre>\n\n\n\n<p>Before we can generate the typed React Query hooks for the GraphQL operations, we need to install these required plugins.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add -D @graphql-codegen\/typescript-operations @graphql-codegen\/typescript @graphql-codegen\/typescript-react-query\n# or \nnpm install -D @graphql-codegen\/typescript-operations @graphql-codegen\/typescript @graphql-codegen\/typescript-react-query\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>@graphql-codegen\/typescript-operations<\/code> &#8211; a plugin for generating the TypeScript types for only used Queries, Mutations, Subscriptions, and Fragments.<\/li>\n\n\n\n<li><code>@graphql-codegen\/typescript<\/code> &#8211; a plugin that generates the base TypeScript types, based on the exact structure of the GraphQL schema.<\/li>\n\n\n\n<li><code>@graphql-codegen\/typescript-react-query<\/code> &#8211; a plugin that generates typed hooks for the GraphQL operations.<\/li>\n<\/ul>\n\n\n\n<p>The GraphQL Code Generator relies on a configuration file which can either be a <code>codegen.yml<\/code> , <code>codegen.js<\/code> or <code>codegen.json<\/code> to manage all possible options.<\/p>\n\n\n\n<p>Now create a <code>codegen.yml<\/code> file with these configuration options to instruct CodeGen on how to generate the codes.<\/p>\n\n\n\n<p><strong>codegen.yml<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nschema: http:\/\/localhost:3000\/api\/graphql\ndocuments: '.\/client\/**\/*.graphql'\ngenerates:\n  .\/client\/generated\/graphql.ts:\n    plugins:\n      - typescript\n      - typescript-operations\n      - typescript-react-query\n    config:\n      fetcher: graphql-request\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>schema<\/code> &#8211; the URL to the GraphQL endpoint.<\/li>\n\n\n\n<li><code>documents<\/code> &#8211; an array of paths to tell CodeGen the location of the GraphQL files. It can also be a plain string like <code>.\/src\/**\/*.graphql<\/code> .<\/li>\n\n\n\n<li><code>generates<\/code> &#8211; this field tells CodeGen where to output the generated code.<\/li>\n\n\n\n<li><code>plugins<\/code> &#8211; this field holds the list of plugins needed by CodeGen to generate the code.<\/li>\n\n\n\n<li><code>fetcher<\/code> this field tells CodeGen the GraphQL client we will be using to make the requests.<\/li>\n<\/ul>\n\n\n\n<p>Next, let&#8217;s add the GraphQL Code Generator script to the <code>package.json<\/code> file and provide it the path to the <code>codegen.yml<\/code> file with the <code>--config<\/code> options.<\/p>\n\n\n\n<p><strong>package.json<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n\"scripts\": {\n    \"generate\": \"graphql-codegen --config codegen.yml\"\n  }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create the GraphQL Mutations and Queries<\/h2>\n\n\n\n<p>GraphQL mutations allow us to modify data on the server. In other words, we can perform insert, update and delete operations using mutations.<\/p>\n\n\n\n<p>Queries on the other hand only allow us to request data from the GrapQL server.<\/p>\n\n\n\n<p>To define a mutation, query, or subscription, we specify the operation type (query, mutation, or subscription) followed by the operation name.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The operation type (query, mutation, or subscription) describes the type of GraphQL operation.<\/li>\n\n\n\n<li>The operation name is simply a meaningful name that we need to specify for each GraphQL operation. The operation name is really important since GraphQL Code Generator will use it to create the React Query hook and the query key.<\/li>\n<\/ul>\n\n\n\n<p>Now create a <code>client\/graphql<\/code> folder and add the following mutations and queries.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sign-up User Mutation<\/h3>\n\n\n\n<p><strong>client\/graphql\/SignUpMutation.graphql<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-graphql\"><code>\nmutation SignUpUser($input: SignUpInput!) {\n  signupUser(input: $input) {\n    status\n    user {\n      name\n      email\n      photo\n      role\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Sign-in User Mutation<\/h3>\n\n\n\n<p><strong>client\/graphql\/LoginMutation.graphql<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-graphql\"><code>\nmutation LoginUser($input: LoginInput!) {\n  loginUser(input: $input) {\n    status\n    access_token\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Get Authenticated User Query<\/h3>\n\n\n\n<p><strong>client\/graphql\/GetMeQuery.graphql<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-graphql\"><code>\nquery GetMe {\n  getMe {\n    status\n    user {\n      _id\n      id\n      email\n      name\n      role\n      photo\n      updatedAt\n      createdAt\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Refresh Access Token Query<\/h3>\n\n\n\n<p><strong>client\/graphql\/RefreshAccessTokenQuery.graphql<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-graphql\"><code>\nquery RefreshAccessToken {\n  refreshAccessToken {\n    status\n    access_token\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Logout User Query<\/h3>\n\n\n\n<p><strong>client\/graphql\/LogoutQuery.graphql<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-graphql\"><code>\nquery LogoutUser {\n  logoutUser\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Generating the Typescript Types &amp; React Query Hooks<\/h2>\n\n\n\n<p>Now that we have all the mutations and queries defined, let&#8217;s execute the generate script we added to the <code>package.json<\/code> file.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn generate\n# or \nnpm run generate\n<\/code><\/pre>\n\n\n\n<p>Once CodeGen has successfully generated the code, you should see a newly-created <code>.\/client\/generated\/graphql.ts<\/code> file containing the Typescript types, and React Query hooks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setup tailwindCss in Next.js<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Install tailwindCss and its peer dependencies<\/h4>\n\n\n\n<p>let&#8217;s begin by installing tailwindCss and its peer dependencies with <strong>npm<\/strong> or <strong>yarn<\/strong>.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nnpm install -D tailwindcss postcss autoprefixer\n# or\nyarn add -D tailwindcss postcss autoprefixer\n<\/code><\/pre>\n\n\n\n<p>Next, run the init command to auto-generate the <code>tailwind.config.js<\/code> and <code>postcss.config.js<\/code> files.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nnpx tailwindcss init -p\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Configure the template paths<\/h4>\n\n\n\n<p>Next, add the paths to the template files in the&nbsp;<code>tailwind.config.js<\/code>&nbsp;file. Also, don&#8217;t forget to add your custom colors and fonts.<\/p>\n\n\n\n<p><strong>tailwind.config.js<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\n\/** @type {import('tailwindcss').Config} *\/\nmodule.exports = {\n  content: ['.\/src\/**\/*.{js,jsx,ts,tsx}'],\n  theme: {\n    extend: {\n      colors: {\n        'ct-dark-600': '#222',\n        'ct-dark-200': '#e5e7eb',\n        'ct-dark-100': '#f5f6f7',\n        'ct-blue-600': '#2363eb',\n        'ct-yellow-600': '#f9d13e',\n      },\n      fontFamily: {\n        Poppins: ['Poppins, sans-serif'],\n      },\n      container: {\n        center: true,\n        padding: '1rem',\n        screens: {\n          lg: '1125px',\n          xl: '1125px',\n          '2xl': '1125px',\n        },\n      },\n    },\n  },\n  plugins: [],\n};\n\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Add the TailwindCSS directives to your CSS File<\/h4>\n\n\n\n<p>Next, add the <code>@tailwind<\/code> directives and font to the&nbsp;<code>.\/styles\/globals.css<\/code>&nbsp;file generated by Next.js. <\/p>\n\n\n\n<p><strong>styles\/globals.css<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-css\"><code>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Poppins:wght@300;400;500;600;700&amp;display=swap');\n\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nhtml {\n  font-family: Poppins, sans-serif;\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Import the CSS File<\/h4>\n\n\n\n<p>Now, import the <code>.\/styles\/globals.css<\/code> file into the&nbsp;<code>.\/pages\/_app.tsx<\/code>&nbsp;file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating React Query, Axios &amp; GraphQL Clients<\/h2>\n\n\n\n<p>Add the Next.js GraphQL API endpoint to the <code>.env.local<\/code> file with  <code>NEXT_PUBLIC_<\/code> prefix.<\/p>\n\n\n\n<p><strong>.env.local<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nNEXT_PUBLIC_GRAPHQL_ENDPOINT=http:\/\/localhost:3000\/api\/graphql\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">GraphQL Request Client<\/h3>\n\n\n\n<p><strong>client\/requests\/graphqlRequestClient.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nimport { GraphQLClient } from 'graphql-request';\nimport { QueryClient } from 'react-query';\n\nconst GRAPHQL_ENDPOINT = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT as string;\n\nconst graphqlRequestClient = new GraphQLClient(GRAPHQL_ENDPOINT, {\n  credentials: 'include',\n  mode: 'cors',\n});\n\nexport const queryClient = new QueryClient({\n  defaultOptions: {\n    queries: {\n      staleTime: 5 * 1000,\n    },\n  },\n});\n\nexport default graphqlRequestClient;\n<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong> You need to set <code>credentials: 'include'<\/code> in the <code>graphql-request<\/code> config options to enable it to include the cookies in the requests.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">Axios GraphQL Request Client<\/h3>\n\n\n\n<p>Axios is an HTTP client library used in both Node.js and the browser. However, Axios also supports GraphQL requests and I decided to include it in this project because I couldn&#8217;t  refresh the access token with <code>graphql-request<\/code> in the<code>getServerSideProps<\/code> function of Next.js<\/p>\n\n\n\n<p>Install the Axios library with the following command:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add axios\n# or\nnpm install axios\n<\/code><\/pre>\n\n\n\n<p><strong>client\/requests\/axiosClient.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport axios from 'axios';\nimport { GetMeQuery } from '..\/generated\/graphql';\nconst BASE_URL = 'http:\/\/localhost:3000\/api\/graphql';\n\nexport const authApi = axios.create({\n  baseURL: BASE_URL,\n  withCredentials: true,\n});\n\nexport const axiosGetMe = async (data: string, access_token: string) =&gt; {\n  const response = await authApi.post&lt;GetMeQuery&gt;(\n    '',\n    { query: data },\n    {\n      headers: {\n        cookie: `access_token=${access_token}`,\n        'Content-Type': 'application\/json',\n      },\n    }\n  );\n  return response.data;\n};\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">State Management with Zustand<\/h2>\n\n\n\n<p>Currently Redux is the dominant React.js state management library, however, you have to write some amount of code to make it work with React. <\/p>\n\n\n\n<p>Some of the flaws of Redux include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Requires actions, dispatch functions, and reducers to be able to update the state.<\/li>\n\n\n\n<li>A provider component needs to be wrapped around the entry point of the application to make the Redux store available to any nested components.<\/li>\n<\/ul>\n\n\n\n<p><a href=\"https:\/\/github.com\/pmndrs\/zustand\" target=\"_blank\" rel=\"noreferrer noopener\">Zustand<\/a> is hands down one of the&nbsp;best&nbsp;libraries for managing client-side states in React. It works seamlessly well&nbsp;out-of-the-box, with zero-config, and can even be used in none React components to retrieve data from the state.<\/p>\n\n\n\n<p>Now create a <code>client\/lib\/types.ts<\/code> file and add the following TypeScript type:<\/p>\n\n\n\n<p><strong>client\/lib\/types.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nexport type IUser = {\n  _id: string;\n  id: string;\n  email: string;\n  name: string;\n  role: string;\n  photo: string;\n  updatedAt: string;\n  createdAt: string;\n};\n\n<\/code><\/pre>\n\n\n\n<p>Run this command to install the Zustand library:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add zustand\n# or\nnpm install zustand\n<\/code><\/pre>\n\n\n\n<p>Next, create a <code>client\/store\/index.ts<\/code> file and add the following code to create the Zustand store.<\/p>\n\n\n\n<p><strong>client\/store\/index.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport create from 'zustand';\nimport { IUser } from '..\/lib\/types';\n\ntype Store = {\n  authUser: IUser | null;\n  uploadingImage: boolean;\n  pageLoading: boolean;\n  setAuthUser: (user: IUser) =&gt; void;\n  setUploadingImage: (isUploading: boolean) =&gt; void;\n  setPageLoading: (isLoading: boolean) =&gt; void;\n};\n\nconst useStore = create&lt;Store&gt;((set) =&gt; ({\n  authUser: null,\n  uploadingImage: false,\n  pageLoading: false,\n  setAuthUser: (user) =&gt; set((state) =&gt; ({ ...state, authUser: user })),\n  setUploadingImage: (isUploading) =&gt;\n    set((state) =&gt; ({ ...state, uploadingImage: isUploading })),\n  setPageLoading: (isLoading) =&gt;\n    set((state) =&gt; ({ ...state, pageLoading: isLoading })),\n}));\n\nexport default useStore;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Creating React Components with TailwindCSS<\/h2>\n\n\n\n<p>Install these packages with either Yarn or NPM:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add tailwind-merge react-cookie\n# or\nnpm install tailwind-merge react-cookie\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/react-cookie\" target=\"_blank\" rel=\"noreferrer noopener\">react-cookie<\/a><\/code> &#8211; a library for accessing and modifying cookies in React<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/tailwind-merge\" target=\"_blank\" rel=\"noreferrer noopener\">tailwind-merge<\/a><\/code> &#8211; a library for merging <a href=\"https:\/\/tailwindcss.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Tailwind CSS<\/a>&nbsp;classes<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Loading Spinner<\/h3>\n\n\n\n<p><strong>client\/components\/Spinner.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport React from 'react';\nimport { twMerge } from 'tailwind-merge';\ntype SpinnerProps = {\n  width?: number;\n  height?: number;\n  color?: string;\n  bgColor?: string;\n};\nconst Spinner: React.FC&lt;SpinnerProps&gt; = ({\n  width = 5,\n  height = 5,\n  color,\n  bgColor,\n}) =&gt; {\n  return (\n    &lt;svg\n      role='status'\n      className={twMerge(\n        'w-5 h-5 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600',\n        `w-${width} h-${height} ${color} ${bgColor}`\n      )}\n      viewBox='0 0 100 101'\n      fill='none'\n      xmlns='http:\/\/www.w3.org\/2000\/svg'\n    &gt;\n      &lt;path\n        d='M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z'\n        fill='currentColor'\n      \/&gt;\n      &lt;path\n        d='M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z'\n        fill='currentFill'\n      \/&gt;\n    &lt;\/svg&gt;\n  );\n};\n\nexport default Spinner;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating the Header Component<\/h3>\n\n\n\n<p><strong>client\/components\/Header.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport Link from 'next\/link';\nimport { useQueryClient } from 'react-query';\nimport { toast } from 'react-toastify';\nimport { LogoutUserQuery, useLogoutUserQuery } from '..\/generated\/graphql';\nimport graphqlRequestClient from '..\/requests\/graphqlRequestClient';\nimport useStore from '..\/store';\nimport Spinner from '.\/Spinner';\n\nconst Header = () =&gt; {\n  const store = useStore();\n  const user = store.authUser;\n\n  const queryClient = useQueryClient();\n  const { refetch } = useLogoutUserQuery(\n    graphqlRequestClient,\n    {},\n    {\n      enabled: false,\n      onSuccess(data: LogoutUserQuery) {\n        queryClient.clear();\n        document.location.href = '\/login';\n      },\n      onError(error: any) {\n        error.response.errors.forEach((err: any) =&gt; {\n          toast(err.message, {\n            type: 'error',\n            position: 'top-right',\n          });\n          queryClient.clear();\n          document.location.href = '\/login';\n        });\n      },\n    }\n  );\n\n  const handleLogout = () =&gt; {\n    refetch();\n  };\n\n  return (\n    &lt;&gt;\n      &lt;header className='bg-white h-20'&gt;\n        &lt;nav className='h-full flex justify-between container items-center'&gt;\n          &lt;div&gt;\n            &lt;Link href='\/' className='text-ct-dark-600 text-2xl font-semibold'&gt;\n              CodevoWeb\n            &lt;\/Link&gt;\n          &lt;\/div&gt;\n          &lt;ul className='flex items-center gap-4'&gt;\n            &lt;li&gt;\n              &lt;Link href='\/' className='text-ct-dark-600'&gt;\n                Home\n              &lt;\/Link&gt;\n            &lt;\/li&gt;\n            {!user &amp;&amp; (\n              &lt;&gt;\n                &lt;li&gt;\n                  &lt;Link href='\/register' className='text-ct-dark-600'&gt;\n                    SignUp\n                  &lt;\/Link&gt;\n                &lt;\/li&gt;\n                &lt;li&gt;\n                  &lt;Link href='\/login' className='text-ct-dark-600'&gt;\n                    Login\n                  &lt;\/Link&gt;\n                &lt;\/li&gt;\n              &lt;\/&gt;\n            )}\n            {user &amp;&amp; (\n              &lt;&gt;\n                &lt;li&gt;\n                  &lt;Link href='\/profile' className='text-ct-dark-600'&gt;\n                    Profile\n                  &lt;\/Link&gt;\n                &lt;\/li&gt;\n                &lt;li className='cursor-pointer'&gt;Create Post&lt;\/li&gt;\n                &lt;li className='cursor-pointer' onClick={handleLogout}&gt;\n                  Logout\n                &lt;\/li&gt;\n              &lt;\/&gt;\n            )}\n          &lt;\/ul&gt;\n        &lt;\/nav&gt;\n      &lt;\/header&gt;\n      &lt;div className='pt-4 pl-2 bg-ct-blue-600 fixed'&gt;\n        {store.pageLoading &amp;&amp; &lt;Spinner color='text-ct-yellow-600' \/&gt;}\n      &lt;\/div&gt;\n    &lt;\/&gt;\n  );\n};\n\nexport default Header;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Full-Screen Loader<\/h3>\n\n\n\n<p><strong>client\/components\/FullScreenLoader.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport Spinner from '.\/Spinner';\n\nconst FullScreenLoader = () =&gt; {\n  return (\n    &lt;div className='w-screen h-screen fixed'&gt;\n      &lt;div className='absolute top-64 left-1\/2 -translate-x-1\/2'&gt;\n        &lt;Spinner width={8} height={8} \/&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  );\n};\n\nexport default FullScreenLoader;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Loading Button<\/h3>\n\n\n\n<p><strong>client\/components\/LoadingButton.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport React from 'react';\nimport Spinner from '.\/Spinner';\n\ntype LoadingButtonProps = {\n  loading: boolean;\n  btnColor?: string;\n  textColor?: string;\n  children: React.ReactNode;\n};\n\nexport const LoadingButton: React.FC&lt;LoadingButtonProps&gt; = ({\n  textColor = 'text-white',\n  btnColor = 'bg-ct-yellow-600',\n  children,\n  loading = false,\n}) =&gt; {\n  return (\n    &lt;button\n      type='submit'\n      className={`w-full py-3 font-semibold ${btnColor} rounded-lg outline-none border-none flex justify-center ${\n        loading ? 'bg-[#ccc]' : ''\n      }`}\n    &gt;\n      {loading ? (\n        &lt;div className='flex items-center gap-3'&gt;\n          &lt;Spinner \/&gt;\n          &lt;span className='text-slate-500 inline-block'&gt;Loading...&lt;\/span&gt;\n        &lt;\/div&gt;\n      ) : (\n        &lt;span className={`${textColor}`}&gt;{children}&lt;\/span&gt;\n      )}\n    &lt;\/button&gt;\n  );\n};\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating an InputField Component with React-Hook-Form<\/h3>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add react-hook-form zod @hookform\/resolvers\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/react-hook-form\" target=\"_blank\" rel=\"noreferrer noopener\">react-hook-form<\/a><\/code> &#8211; a form validation library for React.js<\/li>\n\n\n\n<li><code><a href=\"https:\/\/github.com\/colinhacks\/zod\" target=\"_blank\" rel=\"noreferrer noopener\">zod<\/a><\/code> &#8211; a TypeScript-first schema declaration and validation library<\/li>\n<\/ul>\n\n\n\n<p><strong>client\/components\/FormInput.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport React from 'react';\nimport { useFormContext } from 'react-hook-form';\n\ntype FormInputProps = {\n  label: string;\n  name: string;\n  type?: string;\n};\n\nconst FormInput: React.FC&lt;FormInputProps&gt; = ({\n  label,\n  name,\n  type = 'text',\n}) =&gt; {\n  const {\n    register,\n    formState: { errors },\n  } = useFormContext();\n  return (\n    &lt;div className=''&gt;\n      &lt;label htmlFor={name} className='block text-ct-blue-600 mb-3'&gt;\n        {label}\n      &lt;\/label&gt;\n      &lt;input\n        type={type}\n        placeholder=' '\n        className='block w-full rounded-2xl appearance-none focus:outline-none py-2 px-4'\n        {...register(name)}\n      \/&gt;\n      {errors[name] &amp;&amp; (\n        &lt;span className='text-red-500 text-xs pt-1 block'&gt;\n          {errors[name]?.message as string}\n        &lt;\/span&gt;\n      )}\n    &lt;\/div&gt;\n  );\n};\n\nexport default FormInput;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a FileUpload with Cloudinary and React<\/h3>\n\n\n\n<p>First and foremost, you need to register for an account on <a href=\"https:\/\/cloudinary.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary<\/a> and follow the steps below to configure the upload preset.<\/p>\n\n\n\n<p><strong>Step 1:<\/strong> Click on the Settings icon on the top right side.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"974\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-1024x974.png\" alt=\"cloudinary dashboard\" class=\"wp-image-4418\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-1024x974.png 1024w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-300x285.png 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-768x731.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-100x95.png 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-473x450.png 473w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard.png 1135w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Step 2:<\/strong> Select the &#8220;<strong>Upload<\/strong>&#8221; tab on the settings screen.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"971\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-1024x971.png\" alt=\"cloudinary dashboard upload tab\" class=\"wp-image-4417\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-1024x971.png 1024w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-300x284.png 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-768x728.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-100x95.png 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab-475x450.png 475w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-tab.png 1139w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Step 3:<\/strong> Scroll down and click the &#8220;<strong>Add upload preset<\/strong>&#8221; link.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"983\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-983x1024.png\" alt=\"cloudinary dashboard upload settings\" class=\"wp-image-4416\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-983x1024.png 983w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-288x300.png 288w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-768x800.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-432x450.png 432w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings.png 1037w\" sizes=\"auto, (max-width: 983px) 100vw, 983px\" \/><\/figure>\n\n\n\n<p><strong>Step 4:<\/strong> Input your preset name and change the &#8220;<strong>Signing Mode<\/strong>&#8221; from &#8220;<strong>Signed<\/strong>&#8221; to &#8220;<strong>Unsigned<\/strong>&#8220;.<\/p>\n\n\n\n<p>Enter the preset name as the folder name and click on the &#8220;<strong>Upload Manipulations<\/strong>&#8221; tab.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"984\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-984x1024.png\" alt=\"cloudinary dashboard upload settings preset\" class=\"wp-image-4415\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-984x1024.png 984w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-288x300.png 288w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-768x799.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset-433x450.png 433w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-upload-settings-preset.png 1038w\" sizes=\"auto, (max-width: 984px) 100vw, 984px\" \/><\/figure>\n\n\n\n<p><strong>Step 5:<\/strong> Click on the Edit link to display the &#8220;<strong>Edit Transformation<\/strong>&#8221; popup.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"985\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-985x1024.png\" alt=\"cloudinary dashboard add upload preset\" class=\"wp-image-4412\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-985x1024.png 985w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-289x300.png 289w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-768x798.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset-433x450.png 433w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-add-upload-preset.png 1039w\" sizes=\"auto, (max-width: 985px) 100vw, 985px\" \/><\/figure>\n\n\n\n<p><strong>Step 6:<\/strong> Update the width and height to your preferred sizes and change the image quality type to &#8220;<strong>Automatic &#8211; best quality<\/strong>&#8220;<\/p>\n\n\n\n<p>Next, click the <strong>ok<\/strong> button to save the settings.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"985\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-985x1024.png\" alt=\"cloudinary dashboard traform image\" class=\"wp-image-4414\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-985x1024.png 985w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-289x300.png 289w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-768x798.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image-433x450.png 433w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-traform-image.png 1039w\" sizes=\"auto, (max-width: 985px) 100vw, 985px\" \/><\/figure>\n\n\n\n<p><strong>Step 7:<\/strong> Click on the &#8220;<strong>Save<\/strong>&#8221; button to commit the changes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"983\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-983x1024.png\" alt=\"cloudinary dashboard click on the save button\" class=\"wp-image-4413\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-983x1024.png 983w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-288x300.png 288w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-768x800.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-96x100.png 96w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button-432x450.png 432w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/cloudinary-dashboard-click-on-the-save-button.png 1037w\" sizes=\"auto, (max-width: 983px) 100vw, 983px\" \/><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Keep your &#8220;<strong>upload preset name<\/strong>&#8221; a secret to avoid unsolicited upload of images by random users.<\/p>\n<\/blockquote>\n\n\n\n<p>Now create a <code>client\/components\/FileUpload.tsx<\/code> file and add the following code snippets to handle the image upload request.<\/p>\n\n\n\n<p><strong>client\/components\/FileUpload.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport React, { useCallback } from 'react';\nimport { Controller, useController, useFormContext } from 'react-hook-form';\nimport useStore from '..\/store';\nimport Spinner from '.\/Spinner';\n\nconst CLOUDINARY_UPLOAD_PRESET = 'nextjs-typegraphql';\nconst CLOUDINARY_URL = 'https:\/\/api.cloudinary.com\/v1_1\/Codevo\/image\/upload';\n\ntype FileUpLoaderProps = {\n  name: string;\n};\nconst FileUpLoader: React.FC&lt;FileUpLoaderProps&gt; = ({ name }) =&gt; {\n  const {\n    control,\n    formState: { errors },\n  } = useFormContext();\n  const { field } = useController({ name, control });\n  const store = useStore();\n\n  const onFileDrop = useCallback(\n    async (e: React.SyntheticEvent&lt;EventTarget&gt;) =&gt; {\n      const target = e.target as HTMLInputElement;\n      if (!target.files) return;\n      const newFile = Object.values(target.files).map((file: File) =&gt; file);\n      const formData = new FormData();\n      formData.append('file', newFile[0]);\n      formData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET);\n\n      store.setUploadingImage(true);\n      const data = await fetch(CLOUDINARY_URL, {\n        method: 'POST',\n        body: formData,\n      })\n        .then((res) =&gt; {\n          store.setUploadingImage(false);\n\n          return res.json();\n        })\n        .catch((err) =&gt; {\n          store.setUploadingImage(false);\n          console.log(err);\n        });\n\n      if (data.secure_url) {\n        field.onChange(data.secure_url);\n      }\n    },\n\n    [field, store]\n  );\n\n  return (\n    &lt;Controller\n      name={name}\n      defaultValue=''\n      control={control}\n      render={({ field: { name, onBlur, ref } }) =&gt; (\n        &lt;&gt;\n          &lt;div className='mb-2 flex justify-between items-center'&gt;\n            &lt;div&gt;\n              &lt;span className='block mb-2'&gt;Choose profile photo&lt;\/span&gt;\n              &lt;input\n                className='block text-sm mb-2 text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100'\n                type='file'\n                name={name}\n                onBlur={onBlur}\n                ref={ref}\n                onChange={onFileDrop}\n                multiple={false}\n                accept='image\/jpg, image\/png, image\/jpeg'\n              \/&gt;\n            &lt;\/div&gt;\n            &lt;div&gt;\n              {store.uploadingImage &amp;&amp; &lt;Spinner color='text-yellow-400' \/&gt;}\n            &lt;\/div&gt;\n          &lt;\/div&gt;\n          &lt;p\n            className={`text-red-500 text-xs italic mb-2 ${\n              errors[name] ? 'visible' : 'invisible'\n            }`}\n          &gt;\n            {errors[name] &amp;&amp; (errors[name]?.message as string)}\n          &lt;\/p&gt;\n        &lt;\/&gt;\n      )}\n    \/&gt;\n  );\n};\n\nexport default FileUpLoader;\n<\/code><\/pre>\n\n\n\n<p>To upload images using the <a href=\"https:\/\/cloudinary.com\/documentation\/image_upload_api_reference\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary RESTful image upload Endpoint<\/a>, you are going to need two things:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the Cloudinary cloud name<\/li>\n\n\n\n<li>the upload preset name<\/li>\n<\/ul>\n\n\n\n<p>With these two pieces of information, you can construct the URL like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST https:\/\/api.cloudinary.com\/v1_1\/:cloud_name\/image\/upload<\/code><\/pre>\n\n\n\n<p>You need to replace the <code>:cloud_name<\/code> with your Cloudinary Cloud name and append your upload preset to the formData before making the POST request to upload the image.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">React Query &amp; GraphQL Request: Sign-up User<\/h2>\n\n\n\n<p><strong>pages\/register.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport type { GetServerSideProps, NextPage } from 'next';\nimport { object, string, TypeOf, z } from 'zod';\nimport { zodResolver } from '@hookform\/resolvers\/zod';\nimport { useForm, FormProvider, SubmitHandler } from 'react-hook-form';\nimport { useEffect } from 'react';\nimport FormInput from '..\/client\/components\/FormInput';\nimport Link from 'next\/link';\nimport { LoadingButton } from '..\/client\/components\/LoadingButton';\nimport { useRouter } from 'next\/router';\nimport {\n  SignUpUserMutation,\n  useSignUpUserMutation,\n} from '..\/client\/generated\/graphql';\nimport graphqlRequestClient from '..\/client\/requests\/graphqlRequestClient';\nimport { toast } from 'react-toastify';\nimport FileUpLoader from '..\/client\/components\/FileUpload';\n\nconst registerSchema = object({\n  name: string().min(1, 'Full name is required').max(100),\n  email: string()\n    .min(1, 'Email address is required')\n    .email('Email Address is invalid'),\n  photo: string().min(1, 'Photo is required'),\n  password: string()\n    .min(1, 'Password is required')\n    .min(8, 'Password must be more than 8 characters')\n    .max(32, 'Password must be less than 32 characters'),\n  passwordConfirm: string().min(1, 'Please confirm your password'),\n}).refine((data) =&gt; data.password === data.passwordConfirm, {\n  path: ['passwordConfirm'],\n  message: 'Passwords do not match',\n});\n\nexport type RegisterInput = TypeOf&lt;typeof registerSchema&gt;;\n\nconst RegisterPage: NextPage = () =&gt; {\n  const router = useRouter();\n  const { mutate: SignUpUser, isLoading } = useSignUpUserMutation&lt;Error&gt;(\n    graphqlRequestClient,\n    {\n      onSuccess(data: SignUpUserMutation) {\n        toast(`Welcome ${data.signupUser.user.name}!`, {\n          type: 'success',\n          position: 'top-right',\n        });\n        console.log(data.signupUser.user);\n        router.push('\/login');\n      },\n      onError(error: any) {\n        error.response.errors.forEach((err: any) =&gt; {\n          toast(err.message, {\n            type: 'error',\n            position: 'top-right',\n          });\n        });\n      },\n    }\n  );\n\n  const methods = useForm&lt;RegisterInput&gt;({\n    resolver: zodResolver(registerSchema),\n  });\n\n  const {\n    reset,\n    handleSubmit,\n    formState: { isSubmitSuccessful },\n  } = methods;\n\n  useEffect(() =&gt; {\n    if (isSubmitSuccessful) {\n      reset();\n    }\n    \/\/ eslint-disable-next-line react-hooks\/exhaustive-deps\n  }, [isSubmitSuccessful]);\n\n  const onSubmitHandler: SubmitHandler&lt;RegisterInput&gt; = (values) =&gt; {\n    \/\/ ? Execute the Mutation\n    SignUpUser({ input: values });\n  };\n  return (\n    &lt;section className='py-8 bg-ct-blue-600 min-h-screen grid place-items-center'&gt;\n      &lt;div className='w-full'&gt;\n        &lt;h1 className='text-4xl xl:text-6xl text-center font-[600] text-ct-yellow-600 mb-4'&gt;\n          Welcome to CodevoWeb!\n        &lt;\/h1&gt;\n        &lt;h2 className='text-lg text-center mb-4 text-ct-dark-200'&gt;\n          Sign Up To Get Started!\n        &lt;\/h2&gt;\n        &lt;FormProvider {...methods}&gt;\n          &lt;form\n            onSubmit={handleSubmit(onSubmitHandler)}\n            className='max-w-md w-full mx-auto overflow-hidden shadow-lg bg-ct-dark-200 rounded-2xl p-8 space-y-5'\n          &gt;\n            &lt;FormInput label='Full Name' name='name' \/&gt;\n            &lt;FormInput label='Email' name='email' type='email' \/&gt;\n            &lt;FormInput label='Password' name='password' type='password' \/&gt;\n            &lt;FormInput\n              label='Confirm Password'\n              name='passwordConfirm'\n              type='password'\n            \/&gt;\n            &lt;FileUpLoader name='photo' \/&gt;\n            &lt;span className='block'&gt;\n              Already have an account?{' '}\n              &lt;Link href='\/login'&gt;\n                &lt;a className='text-ct-blue-600'&gt;Login Here&lt;\/a&gt;\n              &lt;\/Link&gt;\n            &lt;\/span&gt;\n            &lt;LoadingButton loading={isLoading} textColor='text-ct-blue-600'&gt;\n              Sign Up\n            &lt;\/LoadingButton&gt;\n          &lt;\/form&gt;\n        &lt;\/FormProvider&gt;\n      &lt;\/div&gt;\n    &lt;\/section&gt;\n  );\n};\n\nexport const getServerSideProps: GetServerSideProps = async () =&gt; {\n  return {\n    props: {\n      requireAuth: false,\n      enableAuth: false,\n    },\n  };\n};\n\nexport default RegisterPage;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">React Query &amp; GraphQL Request: Login User<\/h2>\n\n\n\n<p><strong>pages\/login.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport type { GetServerSideProps, NextPage } from 'next';\nimport { object, string, TypeOf } from 'zod';\nimport { useEffect } from 'react';\nimport { useForm, FormProvider, SubmitHandler } from 'react-hook-form';\nimport { zodResolver } from '@hookform\/resolvers\/zod';\nimport FormInput from '..\/client\/components\/FormInput';\nimport { LoadingButton } from '..\/client\/components\/LoadingButton';\nimport Link from 'next\/link';\nimport {\n  LoginUserMutation,\n  useGetMeQuery,\n  useLoginUserMutation,\n} from '..\/client\/generated\/graphql';\nimport graphqlRequestClient from '..\/client\/requests\/graphqlRequestClient';\nimport { toast } from 'react-toastify';\nimport { useRouter } from 'next\/router';\nimport useStore from '..\/client\/store';\nimport { IUser } from '..\/client\/lib\/types';\n\nconst loginSchema = object({\n  email: string()\n    .min(1, 'Email address is required')\n    .email('Email Address is invalid'),\n  password: string()\n    .min(1, 'Password is required')\n    .min(8, 'Password must be more than 8 characters')\n    .max(32, 'Password must be less than 32 characters'),\n});\n\nexport type LoginInput = TypeOf&lt;typeof loginSchema&gt;;\n\nconst LoginPage: NextPage = () =&gt; {\n  const router = useRouter();\n  const store = useStore();\n\n  const query = useGetMeQuery(\n    graphqlRequestClient,\n    {},\n    {\n      enabled: false,\n      onSuccess: (data) =&gt; {\n        store.setAuthUser(data.getMe.user as IUser);\n      },\n    }\n  );\n\n  const { isLoading, mutate: loginUser } = useLoginUserMutation&lt;Error&gt;(\n    graphqlRequestClient,\n    {\n      onSuccess(data: LoginUserMutation) {\n        toast('Logged in successfully', {\n          type: 'success',\n          position: 'top-right',\n        });\n        query.refetch();\n        router.push('\/profile');\n      },\n      onError(error: any) {\n        error.response.errors.forEach((err: any) =&gt; {\n          toast(err.message, {\n            type: 'error',\n            position: 'top-right',\n          });\n        });\n      },\n    }\n  );\n\n  const methods = useForm&lt;LoginInput&gt;({\n    resolver: zodResolver(loginSchema),\n  });\n\n  const {\n    reset,\n    handleSubmit,\n    formState: { isSubmitSuccessful },\n  } = methods;\n\n  useEffect(() =&gt; {\n    if (isSubmitSuccessful) {\n      reset();\n    }\n    \/\/ eslint-disable-next-line react-hooks\/exhaustive-deps\n  }, [isSubmitSuccessful]);\n\n  const onSubmitHandler: SubmitHandler&lt;LoginInput&gt; = (values) =&gt; {\n    \/\/ ? Executing the loginUser Mutation\n    loginUser({ input: values });\n  };\n  return (\n    &lt;section className='bg-ct-blue-600 min-h-screen grid place-items-center'&gt;\n      &lt;div className='w-full'&gt;\n        &lt;h1 className='text-4xl xl:text-6xl text-center font-[600] text-ct-yellow-600 mb-4'&gt;\n          Welcome Back\n        &lt;\/h1&gt;\n        &lt;h2 className='text-lg text-center mb-4 text-ct-dark-200'&gt;\n          Login to have access\n        &lt;\/h2&gt;\n        &lt;FormProvider {...methods}&gt;\n          &lt;form\n            onSubmit={handleSubmit(onSubmitHandler)}\n            className='max-w-md w-full mx-auto overflow-hidden shadow-lg bg-ct-dark-200 rounded-2xl p-8 space-y-5'\n          &gt;\n            &lt;FormInput label='Email' name='email' type='email' \/&gt;\n            &lt;FormInput label='Password' name='password' type='password' \/&gt;\n\n            &lt;div className='text-right'&gt;\n              &lt;Link href='#' className=''&gt;\n                Forgot Password?\n              &lt;\/Link&gt;\n            &lt;\/div&gt;\n            &lt;LoadingButton loading={isLoading} textColor='text-ct-blue-600'&gt;\n              Login\n            &lt;\/LoadingButton&gt;\n            &lt;span className='block'&gt;\n              Need an account?{' '}\n              &lt;Link href='\/register'&gt;\n                &lt;a className='text-ct-blue-600'&gt;Sign Up Here&lt;\/a&gt;\n              &lt;\/Link&gt;\n            &lt;\/span&gt;\n          &lt;\/form&gt;\n        &lt;\/FormProvider&gt;\n      &lt;\/div&gt;\n    &lt;\/section&gt;\n  );\n};\n\nexport const getServerSideProps: GetServerSideProps = async () =&gt; {\n  return {\n    props: {\n      requireAuth: false,\n      enableAuth: false,\n    },\n  };\n};\n\nexport default LoginPage;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">React Query &amp; GraphQL Request: Middleware Guard<\/h2>\n\n\n\n<p><strong>client\/middleware\/AuthMiddleware.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport React, { useEffect } from 'react';\nimport {\n  useGetMeQuery,\n  useRefreshAccessTokenQuery,\n} from '..\/generated\/graphql';\nimport { IUser } from '..\/lib\/types';\nimport graphqlRequestClient, {\n  queryClient,\n} from '..\/requests\/graphqlRequestClient';\nimport useStore from '..\/store';\n\ntype AuthMiddlewareProps = {\n  children: React.ReactNode;\n  requireAuth?: boolean;\n  enableAuth?: boolean;\n};\n\nconst AuthMiddleware: React.FC&lt;AuthMiddlewareProps&gt; = ({\n  children,\n  requireAuth,\n  enableAuth,\n}) =&gt; {\n  console.log('I was called from AuthMiddleware');\n  const store = useStore();\n  const query = useRefreshAccessTokenQuery(\n    graphqlRequestClient,\n    {},\n    {\n      enabled: false,\n      retry: 1,\n      onError(error: any) {\n        store.setPageLoading(false);\n        document.location.href = '\/login';\n      },\n      onSuccess(data: any) {\n        store.setPageLoading(false);\n        queryClient.refetchQueries('getMe');\n      },\n    }\n  );\n  const { isLoading, isFetching } = useGetMeQuery(\n    graphqlRequestClient,\n    {},\n    {\n      onSuccess: (data) =&gt; {\n        store.setPageLoading(false);\n        store.setAuthUser(data.getMe.user as IUser);\n      },\n      retry: 1,\n      enabled: !!enableAuth,\n      onError(error: any) {\n        store.setPageLoading(false);\n        error.response.errors.forEach((err: any) =&gt; {\n          if (err.message.includes('No access token found')) {\n            query.refetch({ throwOnError: true });\n          }\n        });\n      },\n    }\n  );\n\n  const loading =\n    isLoading || isFetching || query.isLoading || query.isFetching;\n\n  useEffect(() =&gt; {\n    if (loading) {\n      store.setPageLoading(true);\n    }\n    \/\/ eslint-disable-next-line react-hooks\/exhaustive-deps\n  }, [loading]);\n\n  return &lt;&gt;{children}&lt;\/&gt;;\n};\n\nexport default AuthMiddleware;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Creaeting the Profile and Home Pages<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Home Page<\/h3>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport type { NextPage } from 'next';\nimport Header from '..\/client\/components\/Header';\n\nexport const getServerSideProps = async () =&gt; {\n  return {\n    props: {\n      requireAuth: false,\n      enableAuth: false,\n    },\n  };\n};\n\nconst HomePage: NextPage = () =&gt; {\n  return (\n    &lt;&gt;\n      &lt;Header \/&gt;\n      &lt;section className='bg-ct-blue-600 min-h-screen pt-20'&gt;\n        &lt;div className='max-w-4xl mx-auto bg-ct-dark-100 rounded-md h-[20rem] flex justify-center items-center'&gt;\n          &lt;p className='text-5xl font-semibold'&gt;Home Page&lt;\/p&gt;\n        &lt;\/div&gt;\n      &lt;\/section&gt;\n    &lt;\/&gt;\n  );\n};\n\nexport default HomePage;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Profile Page<\/h3>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport type { GetServerSideProps, NextPage } from 'next';\nimport { dehydrate } from 'react-query';\nimport Header from '..\/client\/components\/Header';\nimport {\n  GetMeDocument,\n  GetMeQuery,\n  useGetMeQuery,\n} from '..\/client\/generated\/graphql';\nimport { IUser } from '..\/client\/lib\/types';\nimport { axiosGetMe } from '..\/client\/requests\/axiosClient';\nimport graphqlRequestClient, {\n  queryClient,\n} from '..\/client\/requests\/graphqlRequestClient';\nimport useStore from '..\/client\/store';\n\ntype ProfileProps = {};\n\nconst ProfilePage: NextPage&lt;ProfileProps&gt; = ({}) =&gt; {\n  const store = useStore();\n\n  const user = store.authUser;\n  const query = useGetMeQuery&lt;GetMeQuery, Error&gt;(\n    graphqlRequestClient,\n    {},\n    {\n      retry: 1,\n      onSuccess: (data) =&gt; {\n        store.setAuthUser(data.getMe.user as IUser);\n      },\n    }\n  );\n\n  return (\n    &lt;&gt;\n      &lt;Header \/&gt;\n      &lt;section className='bg-ct-blue-600 min-h-screen pt-20'&gt;\n        &lt;div className='max-w-4xl mx-auto bg-ct-dark-100 rounded-md h-[20rem] flex justify-center items-center'&gt;\n          &lt;div&gt;\n            &lt;p className='text-5xl font-semibold'&gt;Profile Page&lt;\/p&gt;\n            &lt;div className='mt-8'&gt;\n              &lt;p className='mb-4'&gt;ID: {user?.id}&lt;\/p&gt;\n              &lt;p className='mb-4'&gt;Name: {user?.name}&lt;\/p&gt;\n              &lt;p className='mb-4'&gt;Email: {user?.email}&lt;\/p&gt;\n              &lt;p className='mb-4'&gt;Role: {user?.role}&lt;\/p&gt;\n            &lt;\/div&gt;\n          &lt;\/div&gt;\n        &lt;\/div&gt;\n      &lt;\/section&gt;\n    &lt;\/&gt;\n  );\n};\n\nexport const getServerSideProps: GetServerSideProps = async ({ req }) =&gt; {\n  if (req.cookies.access_token) {\n    await queryClient.prefetchQuery(['getMe', {}], () =&gt;\n      axiosGetMe(GetMeDocument, req.cookies.access_token as string)\n    );\n  } else {\n    return {\n      redirect: {\n        destination: '\/login',\n        permanent: false,\n      },\n    };\n  }\n\n  return {\n    props: {\n      dehydratedState: dehydrate(queryClient),\n      requireAuth: true,\n      enableAuth: true,\n    },\n  };\n};\n\nexport default ProfilePage;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Update the App File<\/h2>\n\n\n\n<p><strong>pages\/_app.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport '..\/styles\/globals.css';\nimport 'react-toastify\/dist\/ReactToastify.css';\nimport type { AppProps } from 'next\/app';\nimport { QueryClientProvider, Hydrate } from 'react-query';\nimport { ReactQueryDevtools } from 'react-query\/devtools';\nimport { CookiesProvider } from 'react-cookie';\nimport { queryClient } from '..\/client\/requests\/graphqlRequestClient';\nimport AuthMiddleware from '..\/client\/middleware\/AuthMiddleware';\nimport { ToastContainer } from 'react-toastify';\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  return (\n    &lt;CookiesProvider&gt;\n      &lt;QueryClientProvider client={queryClient}&gt;\n        &lt;Hydrate state={pageProps.dehydratedState}&gt;\n          &lt;AuthMiddleware\n            requireAuth={pageProps.requireAuth}\n            enableAuth={pageProps.enableAuth}\n          &gt;\n            &lt;Component {...pageProps} \/&gt;\n          &lt;\/AuthMiddleware&gt;\n          &lt;ToastContainer \/&gt;\n          &lt;ReactQueryDevtools initialIsOpen={false} \/&gt;\n        &lt;\/Hydrate&gt;\n      &lt;\/QueryClientProvider&gt;\n    &lt;\/CookiesProvider&gt;\n  );\n}\n\nexport default MyApp;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>With this React Query, GraphQL-Request, GraphQL-CodeGen, tailwindCss, and React-Hook-Form example in Typescript, you&#8217;ve learned how to add access and refresh token functionalities to your Next.js applications.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Next.js, GraphQL CodeGen &amp; React Query Source Code<\/h2>\n\n\n\n<p>Check out the complete source code for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/wpcodevo\/nextjs-typegraphql-api\/tree\/nextjs-typegraphql-jwt-auth\" target=\"_blank\" rel=\"noreferrer noopener\">GraphQL Next.js API with TypeGraphQL<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/wpcodevo\/nextjs-typegraphql-api\/tree\/nextjs-auth-react-query\" target=\"_blank\" rel=\"noreferrer noopener\">Full-Stack JWT Auth with Next.js, React Query, Apollo Server, and TypeGraphQL<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>GraphQL Code Generator is a plugin-based toolkit for automating and generating full-typed GraphQL operations. This article will teach you how to add access and refresh&#8230;<\/p>\n","protected":false},"author":1,"featured_media":4815,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[76],"tags":[75,77,42,55],"class_list":["post-4739","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-nextjs","tag-graphql","tag-nextjs","tag-nodejs-api","tag-reactjs"],"acf":[],"_links":{"self":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4739","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/comments?post=4739"}],"version-history":[{"count":1,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4739\/revisions"}],"predecessor-version":[{"id":11273,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4739\/revisions\/11273"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media\/4815"}],"wp:attachment":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media?parent=4739"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/categories?post=4739"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/tags?post=4739"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}