Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5a21617
configure graphql-codegen
rudransh-shrivastava Aug 29, 2025
8402bf6
refactor query names to be unique
rudransh-shrivastava Aug 29, 2025
9a3a5e8
Update code (sort alphabetically)
rudransh-shrivastava Aug 29, 2025
441e25c
ignore graphql-codegen generated files
rudransh-shrivastava Aug 29, 2025
5c8b6e1
Run graphql-codegen
rudransh-shrivastava Aug 29, 2025
55f86cc
remove fetchCsrfTokenServer and use a config constructor
rudransh-shrivastava Aug 29, 2025
0e7055d
Update code
rudransh-shrivastava Aug 30, 2025
dd5d2fe
use near-operation-file-preset
rudransh-shrivastava Aug 30, 2025
1fc0818
use typed-document-node plugin
rudransh-shrivastava Aug 30, 2025
09b8ca5
Update code (sort alphabetically)
rudransh-shrivastava Aug 30, 2025
a239467
Update code
rudransh-shrivastava Aug 30, 2025
d71e394
add graphql-codegen generated types to end-of-file-fixer
rudransh-shrivastava Aug 30, 2025
7bb3bc6
add hook for graphql-codegen for schema validation
rudransh-shrivastava Aug 31, 2025
f15fe68
Update code
rudransh-shrivastava Aug 31, 2025
e17d036
Merge branch 'main' into feature/integrate-graphql-codegen
rudransh-shrivastava Aug 31, 2025
cb90877
skip graphql-codegen pre-commit hook
rudransh-shrivastava Aug 31, 2025
bcf8d26
add graphql-codegen
rudransh-shrivastava Aug 31, 2025
4babd73
Merge branch 'main' into feature/integrate-graphql-codegen
arkid15r Sep 2, 2025
f1c7653
add generate-graphql-types to make check
rudransh-shrivastava Sep 2, 2025
3316cce
run make check
rudransh-shrivastava Sep 2, 2025
6bb7ed0
Update code
arkid15r Sep 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.pnpm-store/
pnpm-lock.yaml
src/types/__generated__/**/*
11 changes: 10 additions & 1 deletion frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,16 @@ const eslintConfig = [
...compat.extends('next/typescript'),
react.configs.flat['jsx-runtime'],
{
ignores: ['.cache', '.next', '.pnpm-store', 'node_modules', 'build', 'dist', 'next-env.d.ts'],
ignores: [
'.cache',
'.next',
'.pnpm-store',
'node_modules',
'build',
'dist',
'next-env.d.ts',
'src/types/__generated__/**/*',
],
},
js.configs.recommended,
{
Expand Down
62 changes: 62 additions & 0 deletions frontend/graphql-codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { CodegenConfig } from '@graphql-codegen/cli'

const PUBLIC_API_URL = process.env.PUBLIC_API_URL || 'http://localhost:8000'

export default (async (): Promise<CodegenConfig> => {
const response = await fetch(`${PUBLIC_API_URL}/csrf/`, {
method: 'GET',
})

if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
const data = await response.json()
const csrfToken = data.csrftoken

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden CSRF extraction and clear timeout.

Be resilient to different payload shapes and fall back to Set-Cookie. Fail fast if still missing.

-  if (!response.ok) {
+  clearTimeout(timeout)
+  if (!response.ok) {
     throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
   }
-  const data = await response.json()
-  const csrfToken = data.csrftoken
+  type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
+  const data = (await response.json().catch(() => ({}))) as CsrfResponse
+  let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
+  if (!csrfToken) {
+    const setCookie = response.headers.get('set-cookie') ?? ''
+    const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
+    if (m) csrfToken = m[1]
+  }
+  if (!csrfToken) {
+    throw new Error('Failed to extract CSRF token from CSRF endpoint response')
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
const data = await response.json()
const csrfToken = data.csrftoken
clearTimeout(timeout)
if (!response.ok) {
throw new Error(`Failed to fetch CSRF token: ${response.status} ${response.statusText}`)
}
type CsrfResponse = { csrftoken?: string; csrfToken?: string; token?: string }
const data = (await response.json().catch(() => ({}))) as CsrfResponse
let csrfToken = data.csrftoken ?? data.csrfToken ?? data.token
if (!csrfToken) {
const setCookie = response.headers.get('set-cookie') ?? ''
const m = setCookie.match(/(?:^|;\s*)csrftoken=([^;]+)/i)
if (m) csrfToken = m[1]
}
if (!csrfToken) {
throw new Error('Failed to extract CSRF token from CSRF endpoint response')
}
🤖 Prompt for AI Agents
In frontend/graphql-codegen.ts around lines 11 to 16, the code assumes the CSRF
token is at data.csrftoken and doesn't clear the fetch timeout or handle
alternate payloads; update the logic to: parse JSON safely (guarding for
data.csrftoken, data.csrfToken, data.token, or nested properties), if JSON
parsing fails or none of those fields exist, check the
response.headers.get('set-cookie') (or other cookie headers) for a csrf token
fallback, and ensure any timeout/abort controller is cleared or aborted cleanup
is performed; if after these attempts the token is still missing, throw an
explicit error immediately to fail fast.

return {
documents: ['src/**/*.{ts,tsx}', '!src/types/__generated__/**'],
generates: {
'./src/': {
config: {
avoidOptionals: {
// Use `null` for nullable fields instead of optionals
field: true,
// Allow nullable input fields to remain unspecified
inputValue: false,
},
// Use `unknown` instead of `any` for unconfigured scalars
defaultScalarType: 'unknown',
// Apollo Client always includes `__typename` fields
nonOptionalTypename: true,
// Apollo Client doesn't add the `__typename` field to root types so
// don't generate a type for the `__typename` for root operation types.
skipTypeNameForRoot: true,
},
// Order of plugins matter
plugins: ['typescript-operations', 'typed-document-node'],
preset: 'near-operation-file',
presetConfig: {
// This should be the file generated by the "typescript" plugin above,
// relative to the directory specified for this configuration
baseTypesPath: './types/__generated__/graphql.ts',
// Relative to the source files
folder: '../../types/__generated__',
},
},
'./src/types/__generated__/graphql.ts': {
plugins: ['typescript'],
},
},
// Don't exit with non-zero status when there are no documents
ignoreNoDocuments: true,
overwrite: true,
schema: {
[`${PUBLIC_API_URL}/graphql/`]: {
headers: {
Cookie: `csrftoken=${csrfToken}`,
'X-CSRFToken': csrfToken,
},
},
},
}
})()
7 changes: 7 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dev": "next dev --port 3000",
"format": "prettier --log-level warn --write .",
"format:check": "prettier --check .",
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Generate types automatically during builds.

Prevent stale/missing types by invoking codegen before build.

   "scripts": {
-    "build": "next build",
+    "build": "pnpm run graphql-codegen && next build",
     "build:turbo": "next build --turbo",
@@
-    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
+    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
+    "predev": "pnpm run graphql-codegen",
+    "pretest:unit": "pnpm run graphql-codegen",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
"scripts": {
"build": "pnpm run graphql-codegen && next build",
"build:turbo": "next build --turbo",
"graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
"predev": "pnpm run graphql-codegen",
"pretest:unit": "pnpm run graphql-codegen",
}
🤖 Prompt for AI Agents
In frontend/package.json around line 11, the project invokes graphql-codegen via
a standalone script but does not ensure types are generated before building;
update package.json scripts to run codegen automatically before build—either add
a "prebuild" script that runs "graphql-codegen --config graphql-codegen.ts" or
prepend the build script with the codegen command (e.g., "graphql-codegen
--config graphql-codegen.ts && <existing build command>") so types are always
generated during CI/local builds.

Copy link
Collaborator Author

@rudransh-shrivastava rudransh-shrivastava Aug 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this possible if we run backend separately? if we invoke codegen before build it may fail as backend may or may not be available. Codegen requires a server to query the GraphQL endpoint

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rudransh-shrivastava You're absolutely right! That's a critical oversight on my part. Running codegen during build would indeed fail when the backend isn't available, which is common in CI/CD pipelines or local development scenarios.

Here are better approaches to handle this:

Option 1: Use a static schema file

// In graphql-codegen.ts, replace the schema URL with a local file
- schema: `${PUBLIC_API_URL}/graphql/`,
+ schema: './schema.graphql',

Option 2: Make codegen conditional

{
  "scripts": {
    "graphql-codegen": "graphql-codegen --config graphql-codegen.ts",
    "graphql-codegen:safe": "graphql-codegen --config graphql-codegen.ts || echo 'Codegen skipped - server unavailable'",
    "build": "pnpm run graphql-codegen:safe && next build"
  }
}

Option 3: Separate CI step
Run codegen only when backend is available (e.g., in a specific CI job) and commit the generated types.

Given that you've already committed the generated types, Option 3 seems to align with your current approach. The types would be generated when the backend is available and committed to the repo.

What's your preference for handling this in your deployment pipeline?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. to get a schema.graphql file, I run into the same problem. I need a backend server to generate that file.

I would like to know if there's a way to run graphql-codegen after backend is available? This is for local development purposes. I am assuming that for CI jobs -- all generated files are already present.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • No changes needed to your current graphql-codegen.ts configuration
  • Generated files remain committed for CI/CD as you intended

The first solution with wait-on + concurrently is probably your best bet since it handles the server dependency gracefully and provides a smooth development experience.

"lighthouse-ci": "lhci autorun",
"lighthouse-ci:desktop": "lhci autorun --collect.settings.preset=desktop",
"lint": "eslint . --config eslint.config.mjs --fix --max-warnings=0",
Expand All @@ -23,6 +24,7 @@
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^3.0.1",
"@graphql-typed-document-node/core": "^3.2.0",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does apollo pick up the generated types automagically based on the location?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, We need to import the types in each file where useQuery hook is used.
Example

Is it okay if I refactor all this in a different PR? I will need to update the tests too. I believe this refactor should complete the apollo migration.

For now, the generated files are unused.

It's recommended by apollo to separate out queries (one generated file for each query/mutation file) for larger applications. If we don't do this, all the queries and mutation are generated in the graphql.ts file.

"@heroui/button": "^2.2.24",
"@heroui/modal": "^2.2.21",
"@heroui/react": "^2.8.2",
Expand Down Expand Up @@ -68,6 +70,11 @@
"@axe-core/react": "^4.10.2",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.34.0",
"@graphql-codegen/cli": "^5.0.7",
"@graphql-codegen/near-operation-file-preset": "^3.1.0",
"@graphql-codegen/typed-document-node": "^5.1.2",
"@graphql-codegen/typescript": "^4.1.6",
"@graphql-codegen/typescript-operations": "^4.6.1",
"@lhci/cli": "^0.15.1",
"@playwright/test": "^1.55.0",
"@swc/core": "^1.13.5",
Expand Down
Loading