diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5e42d18fb7..ab6a833602 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,18 +1,14 @@ /* eslint-env node */ const CODE_EXT = "js,jsx,cjs,mjs,ts,tsx,cts,mts" - const MARKDOWN_EXT = "md,mdx" module.exports = { root: true, + plugins: ["@graphql-eslint", "mdx", "@typescript-eslint", "tailwindcss"], overrides: [ { files: [`**/*.{${CODE_EXT}}`], - // TODO: extract graphql documents from code files - // to lint graphql documents marked with /* GraphQL */ comments inside js/ts codeblocks in markdown - // processor: '@graphql-eslint/graphql', - // plugins: ['@graphql-eslint'], extends: [ "eslint:recommended", "plugin:@typescript-eslint/recommended", @@ -34,7 +30,6 @@ module.exports = { }, ], "prefer-const": ["error", { destructuring: "all" }], - // TODO: fix below "prefer-rest-params": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": "off", @@ -51,27 +46,45 @@ module.exports = { { files: [`**/*.{${MARKDOWN_EXT}}`], parser: "eslint-mdx", + extends: ["plugin:mdx/recommended"], processor: "mdx/remark", - plugins: ["mdx"], parserOptions: { ecmaVersion: 13, sourceType: "module", }, settings: { "mdx/code-blocks": true, + "mdx/language-mapper": { + js: "espree", + graphql: "@graphql-eslint/parser", + ts: "@typescript-eslint/parser", + typescript: "@typescript-eslint/parser", + }, }, rules: { "mdx/remark": "error", }, }, { - files: [`**/*.{${MARKDOWN_EXT}}/*.{${CODE_EXT}}`], + files: ["**/*.graphql"], + parser: "@graphql-eslint/parser", rules: { - "no-unused-labels": "off", - "no-undef": "off", - "no-redeclare": "off", - "no-import-assign": "off", - "no-prototype-builtins": "off", + "@graphql-eslint/no-syntax-errors": "error", + "@graphql-eslint/unique-operation-name": "error", + "@graphql-eslint/unique-fragment-name": "error", + "@graphql-eslint/no-anonymous-operations": "warn", + "@graphql-eslint/lone-anonymous-operation": "error", + "@graphql-eslint/no-duplicate-fields": "error", + "@graphql-eslint/no-unused-fragments": "warn", + "@graphql-eslint/no-duplicate-fragment-names": "error", + "@graphql-eslint/no-undefined-variables": "error", + "@graphql-eslint/unique-variable-names": "error", + }, + }, + { + files: [`**/*.{${CODE_EXT}}`, `**/*.{${MARKDOWN_EXT}}`], + parserOptions: { + plugins: ["graphql"], }, }, { @@ -84,9 +97,5 @@ module.exports = { "mdx/remark": "off", }, }, - { - files: ["**/*.graphql"], - parser: "@graphql-eslint/eslint-plugin", - }, ], } diff --git a/.github/workflows/docs-validation.yml b/.github/workflows/docs-validation.yml new file mode 100644 index 0000000000..77dad776b8 --- /dev/null +++ b/.github/workflows/docs-validation.yml @@ -0,0 +1,64 @@ +# Docs validation workflow runs on each PR on main w/ broken link checker +# and code snippet validation + +name: Docs validation + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: +link-check: + name: Broken link checker + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build static site + run: pnpm build + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Install lychee + run: cargo install lychee + + - name: Check links + run: lychee --verbose --no-progress './out/**/*.html' + +code-validate: + name: Code snippet and GraphQL validation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run validation w/ annotations + run: pnpm lint:docs:ci + + - name: Validate code snippets + run: pnpm validate:snippets diff --git a/.prettierignore b/.prettierignore index 896ab5f8f4..ebb39d2d73 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,4 +3,6 @@ pnpm-lock.yaml *.mdx !src/pages/blog/2024-04-11-announcing-new-graphql-website/index.mdx !src/pages/blog/2024-08-15-graphql-local-initiative.mdx +!src/pages/community/foundation/community-grant.mdx +!src/pages/blog/2025-06-01-graphiql-4/index.mdx *.jpg diff --git a/.vscode/settings.json b/.vscode/settings.json index cb56bf9fab..02d49400e5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,6 @@ "typescript.tsdk": "node_modules/typescript/lib", "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "tailwindCSS.classFunctions": ["clsx"] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f351ccc8f..06b99b5de1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,7 @@ There are many ways to get involved. Follow this guide and feel free to [reach o - [Development guide](#development-guide) - [Running the site locally](#running-the-site-locally) + - [Checking for broken links](#checking-for-broken-links) - [Branching](#branching) - [Project structure](#project-structure) - [Publishing the updated site](#publishing-the-updated-site) @@ -53,6 +54,21 @@ Finally, open http://localhost:3000 to view it in the browser. The GraphQL website is built with [Nextra](https://nextra.site). This means that a hot-reloading development environment will be accessible by default. +### Checking for broken links + +We use [Lychee](https://github.com/lycheeverse/lychee), a Rust-based CLI tool, to check for broken links in our documentation. + +To install Lychee locally: + +1. Install Rust: https://www.rust-lang.org/tools/install +2. After installing Rust, run: + +```bash +cargo install lychee +``` + +With Rust and Lychee installed, run the link checker: `pnpm run check:links`. + ### Branching Active development for graphql.org happens on the `source` branch. Be sure to create any new branches or direct any pull requests back to `source`. diff --git a/next.config.js b/next.config.js index bfd990f81e..24baa11c51 100644 --- a/next.config.js +++ b/next.config.js @@ -31,12 +31,38 @@ export default withLess( rule.test?.test?.(".svg"), ) - fileLoaderRule.exclude = ALLOWED_SVG_REGEX + fileLoaderRule.exclude = /\.svg$/i + + config.module.rules.push( + // All .svg from /icons/ and with ?svgr are going to be processed by @svgr/webpack + { + test: ALLOWED_SVG_REGEX, + use: ["@svgr/webpack"], + }, + { + test: /\.svg$/i, + exclude: ALLOWED_SVG_REGEX, + resourceQuery: /svgr/, + use: [ + { + loader: "@svgr/webpack", + options: { + dimensions: false, // **adds** viewBox. + }, + }, + ], + }, + // Otherwise, we use the default file loader + { + ...fileLoaderRule, + test: /\.svg$/i, + exclude: ALLOWED_SVG_REGEX, + resourceQuery: { + not: [...fileLoaderRule.resourceQuery.not, /svgr/], + }, + }, + ) - config.module.rules.push({ - test: ALLOWED_SVG_REGEX, - use: ["@svgr/webpack"], - }) return config }, output: "export", diff --git a/package.json b/package.json index 477d1e29e4..b7d60df083 100644 --- a/package.json +++ b/package.json @@ -6,24 +6,29 @@ "packageManager": "pnpm@9.15.2", "scripts": { "build": "next build && next-image-export-optimizer", + "check:links": "lychee --verbose --no-progress './src/pages/**/*.mdx' --base https://graphql.org", "dev": "next", "format": "pnpm format:check --write", "format:check": "prettier --cache --check .", "lint": "eslint --ignore-path .gitignore .", + "lint:docs": "eslint --ignore-path .gitignore src/pages/learn --format stylish", + "lint:docs:ci": "eslint --ignore-path .gitignore src/pages/learn --format eslint-formatter-github", "postbuild": "next-sitemap", "prebuild": "tsx src/get-github-info.ts", "start": "next start", - "test": "echo \"no tests\" && exit 1" + "test": "echo \"no tests\" && exit 1", + "validate:snippets": "node scripts/validate-snippets.js" }, "dependencies": { "@graphql-tools/schema": "10.0.15", "@headlessui/react": "^1.7.17", "@radix-ui/react-radio-group": "^1.1.3", + "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/nesting": "0.0.0-insiders.565cd3e", "@tailwindcss/typography": "^0.5.10", "autoprefixer": "^10.4.17", "clsx": "^2.1.0", - "codemirror": "5.65.1", + "codemirror": "^5.65.19", "codemirror-graphql": "1.3.2", "date-fns": "^2.30.0", "fast-glob": "^3.3.2", @@ -35,6 +40,7 @@ "lucide-react": "^0.469.0", "markdown-to-jsx": "^7.4.0", "marked": "5.1.2", + "motion": "^12.11.0", "next": "^14.2.5", "next-image-export-optimizer": "^1.12.3", "next-query-params": "^5.0.0", @@ -49,6 +55,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-medium-image-zoom": "5.2.13", + "react-use-measure": "^2.1.7", "rss": "1.2.2", "server-only": "0.0.1", "string-similarity": "^4.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aac6f53025..c2cde5d2db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,9 @@ importers: '@radix-ui/react-radio-group': specifier: ^1.1.3 version: 1.2.2(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tailwindcss/container-queries': + specifier: ^0.1.1 + version: 0.1.1(tailwindcss@3.4.17) '@tailwindcss/nesting': specifier: 0.0.0-insiders.565cd3e version: 0.0.0-insiders.565cd3e(postcss@8.4.49) @@ -35,11 +38,11 @@ importers: specifier: ^2.1.0 version: 2.1.1 codemirror: - specifier: 5.65.1 - version: 5.65.1 + specifier: ^5.65.19 + version: 5.65.19 codemirror-graphql: specifier: 1.3.2 - version: 1.3.2(@codemirror/language@0.20.2)(codemirror@5.65.1)(graphql@16.10.0) + version: 1.3.2(@codemirror/language@0.20.2)(codemirror@5.65.19)(graphql@16.10.0) date-fns: specifier: ^2.30.0 version: 2.30.0 @@ -70,6 +73,9 @@ importers: marked: specifier: 5.1.2 version: 5.1.2 + motion: + specifier: ^12.11.0 + version: 12.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: specifier: ^14.2.5 version: 14.2.22(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -112,6 +118,9 @@ importers: react-medium-image-zoom: specifier: 5.2.13 version: 5.2.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-use-measure: + specifier: ^2.1.7 + version: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rss: specifier: 1.2.2 version: 1.2.2 @@ -1703,6 +1712,11 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@tailwindcss/container-queries@0.1.1': + resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} + peerDependencies: + tailwindcss: '>=3.2.0' + '@tailwindcss/nesting@0.0.0-insiders.565cd3e': resolution: {integrity: sha512-WhHoFBx19TnH/c+xLwT/sxei6+4RpdfiyG3MYXfmLaMsADmVqBkF7B6lDalgZD9YdM459MF7DtxVbWkOrV7IaQ==} peerDependencies: @@ -2120,8 +2134,8 @@ packages: codemirror: ^5.65.3 graphql: ^15.5.0 || ^16.0.0 - codemirror@5.65.1: - resolution: {integrity: sha512-s6aac+DD+4O2u1aBmdxhB7yz2XU7tG3snOyQ05Kxifahz7hoxnfxIRHxiCSEv3TUC38dIVH8G+lZH9UWSfGQxA==} + codemirror@5.65.19: + resolution: {integrity: sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==} codsen-utils@1.6.4: resolution: {integrity: sha512-PDyvQ5f2PValmqZZIJATimcokDt4JjIev8cKbZgEOoZm+U1IJDYuLeTcxZPQdep99R/X0RIlQ6ReQgPOVnPbNw==} @@ -2731,6 +2745,20 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + framer-motion@12.11.0: + resolution: {integrity: sha512-BaBPmkhaC2l0n619Kt1nQaxSdUdyyz5V1Z7EKJ1CcraOTZitgVx0RTbL8lmg2XesaFi6o8MPBIhkWDIvzDpGaQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3596,6 +3624,26 @@ packages: mj-context-menu@0.6.1: resolution: {integrity: sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==} + motion-dom@12.11.0: + resolution: {integrity: sha512-CItkGYJenn5ZsbzTX0D9mE0UWdjdd9r535FrxEXhzR8Kwa9I2dLr1uhEJgQPWbgaIJ6i0sNFnf2T9NvVDWQVBw==} + + motion-utils@12.9.4: + resolution: {integrity: sha512-BW3I65zeM76CMsfh3kHid9ansEJk9Qvl+K5cu4DVHKGsI52n76OJ4z2CUJUV+Mn3uEP9k1JJA3tClG0ggSrRcg==} + + motion@12.11.0: + resolution: {integrity: sha512-1DIh+uBh2Ledv8VlJfveLuE+6tTAkLqRxhBHQSH6Ct8PxcZpUWY7z9E34L3LvnGbXp8u97hGSjeDsmvmVrjOeQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -4054,6 +4102,15 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-use-measure@2.1.7: + resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} + peerDependencies: + react: '>=16.13' + react-dom: '>=16.13' + peerDependenciesMeta: + react-dom: + optional: true + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -6456,6 +6513,10 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.8.1 + '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.17)': + dependencies: + tailwindcss: 3.4.17 + '@tailwindcss/nesting@0.0.0-insiders.565cd3e(postcss@8.4.49)': dependencies: postcss: 8.4.49 @@ -6892,14 +6953,14 @@ snapshots: clsx@2.1.1: {} - codemirror-graphql@1.3.2(@codemirror/language@0.20.2)(codemirror@5.65.1)(graphql@16.10.0): + codemirror-graphql@1.3.2(@codemirror/language@0.20.2)(codemirror@5.65.19)(graphql@16.10.0): dependencies: '@codemirror/language': 0.20.2 - codemirror: 5.65.1 + codemirror: 5.65.19 graphql: 16.10.0 graphql-language-service: 5.2.0(graphql@16.10.0) - codemirror@5.65.1: {} + codemirror@5.65.19: {} codsen-utils@1.6.4: dependencies: @@ -7593,6 +7654,15 @@ snapshots: fraction.js@4.3.7: {} + framer-motion@12.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + motion-dom: 12.11.0 + motion-utils: 12.9.4 + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -8886,6 +8956,20 @@ snapshots: mj-context-menu@0.6.1: {} + motion-dom@12.11.0: + dependencies: + motion-utils: 12.9.4 + + motion-utils@12.9.4: {} + + motion@12.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + framer-motion: 12.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + mri@1.2.0: {} ms@2.1.2: {} @@ -9332,6 +9416,12 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react-use-measure@2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index cac8a5aaf9..0000000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -packages: - - "website" diff --git a/public/img/conf/Sponsors/Grafbase.svg b/public/img/conf/Sponsors/Grafbase.svg new file mode 100644 index 0000000000..2b99439008 --- /dev/null +++ b/public/img/conf/Sponsors/Grafbase.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/img/conf/Sponsors/Tyk.svg b/public/img/conf/Sponsors/Tyk.svg index 5d9487148a..06fa8b1397 100644 --- a/public/img/conf/Sponsors/Tyk.svg +++ b/public/img/conf/Sponsors/Tyk.svg @@ -1,18 +1,7 @@ - - - - - - - - - \ No newline at end of file + + + + + + diff --git a/scripts/validate-snippets.js b/scripts/validate-snippets.js new file mode 100644 index 0000000000..8bd70c09bf --- /dev/null +++ b/scripts/validate-snippets.js @@ -0,0 +1,158 @@ +#!/usr/bin/env node + +import fs from "node:fs" +import path from "node:path" +import glob from "glob" +import { parse } from "graphql" +import chalk from "chalk" +import { fileURLToPath } from "node:url" + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const projectRoot = path.resolve(__dirname, "../") + +const MDX_GLOB = "./src/pages/learn/**/*.mdx" +const CODE_BLOCK_REGEX = /^(`{3,})(\w+)\s*\n([\s\S]*?)\r?\n\1$/gm +const IGNORE_COMMENT = "snippet-ignore" + +let totalFiles = 0 +let totalSnippets = 0 +let totalErrors = 0 + +// TODO: Add JS linting after JS code snippet modernization +// async function lintJavaScript(code, filePath) { +// const eslint = new ESLint({ +// useEslintrc: true, +// baseConfig: { +// parserOptions: { +// ecmaVersion: "latest", +// sourceType: "module", +// }, +// }, +// }) + +// let preparedCode = code.trim() + +// if (preparedCode.startsWith("function")) { +// preparedCode = "/* eslint-disable no-unused-vars */\n" + preparedCode +// } + +// const results = await eslint.lintText(preparedCode, { filePath }) +// return results.flatMap(result => result.messages) +// } + +function validateGraphQL(code) { + try { + parse(code) + return [] + } catch (error) { + return [{ message: error.message }] + } +} + +function extractSnippets(content, filePath) { + const snippets = [] + let match + + while ((match = CODE_BLOCK_REGEX.exec(content)) !== null) { + const [fullMatch, openingBackticks, lang, code] = match + const beforeBlock = content.slice(0, match.index) + const lineNumber = beforeBlock.split(/\r?\n/).length + + if (beforeBlock.includes(IGNORE_COMMENT)) { + continue + } + + snippets.push({ lang, code, lineNumber, filePath }) + } + + return snippets +} + +async function validateSnippet(snippet) { + const { lang, code, lineNumber, filePath } = snippet + + if (!code.trim()) return [] + + // TODO: Add section after JS code snippet modernization + // if (["js", "javascript", "ts", "typescript"].includes(lang)) { + // const messages = await lintJavaScript(code, filePath) + // return messages.map(msg => ({ + // type: "JS/TS", + // file: filePath, + // line: lineNumber + (msg.line || 1), + // message: msg.message, + // })) + // } + + if (lang === "graphql") { + const messages = validateGraphQL(code) + return messages.map(msg => ({ + type: "GraphQL", + file: filePath, + line: lineNumber + (msg.line || 1), + message: msg.message, + })) + } + + return [] +} + +async function main() { + console.log(`Validating code snippets in: ${projectRoot}/${MDX_GLOB}`) + + const files = glob.sync(MDX_GLOB, { cwd: projectRoot }) + totalFiles = files.length + + if (totalFiles === 0) { + console.log(chalk.green("No MDX files found to validate.")) + return + } + + const errors = [] + + for (const file of files) { + const content = fs.readFileSync(file, "utf8") + const snippets = extractSnippets(content, file) + totalSnippets += snippets.length + + for (const snippet of snippets) { + const snippetErrors = await validateSnippet(snippet) + errors.push(...snippetErrors) + } + } + + totalErrors = errors.length + + if (totalErrors > 0) { + errors.forEach(err => { + const errorMessage = `${err.type} Error in ${err.file} at line ${err.line}: ${err.message}` + console.error(chalk.red(errorMessage)) + + if (process.env.GITHUB_ACTIONS) { + console.log(`::error file=${err.file},line=${err.line}::${err.message}`) + } + }) + + console.error( + chalk.red("\nCode snippet validation failed. Check error logs."), + ) + console.error(`Files checked: ${totalFiles}`) + console.error(`Snippets checked: ${totalSnippets}`) + console.error(`Errors found: ${totalErrors}`) + process.exit(1) + } else { + console.log( + chalk.green( + "\nCode snippet validation passed. All code snippets are valid.", + ), + ) + console.log(`Files checked: ${totalFiles}`) + console.log(`Snippets checked: ${totalSnippets}`) + } +} + +main().catch(err => { + console.error(err) + process.exit(1) +}) diff --git a/src/app/colors.css b/src/app/colors.css new file mode 100644 index 0000000000..95ec008b24 --- /dev/null +++ b/src/app/colors.css @@ -0,0 +1,40 @@ +:root, +.light { + --color-pri-lighter: 319 100% 90%; + --color-pri-light: 318 100% 80%; + --color-pri-base: 319 100% 44.1%; + --color-pri-dark: 319 100% 30%; + --color-pri-darker: 319 100% 20%; + + --color-sec-lighter: 79 80% 90%; + --color-sec-light: 79 82% 80%; + --color-sec-base: 79 90% 65%; + --color-sec-dark: 79 98% 37%; + --color-sec-darker: 79 98% 23%; + + --color-neu-0: 0 0% 100%; + --color-neu-50: 75 57% 97%; + --color-neu-100: 75 15% 95%; + --color-neu-200: 77 14% 90%; + --color-neu-300: 76 14% 85%; + --color-neu-400: 77 14% 80%; + --color-neu-500: 74 14% 70%; + --color-neu-600: 76 15% 60%; + --color-neu-700: 76 15% 40%; + --color-neu-800: 77 14% 20%; + --color-neu-900: 75 15% 5%; +} + +.dark { + --color-neu-900: 0 0% 100%; + --color-neu-800: 75 57% 97%; + --color-neu-700: 75 15% 95%; + --color-neu-600: 77 14% 90%; + --color-neu-500: 76 14% 85%; + --color-neu-400: 77 14% 80%; + --color-neu-300: 74 14% 70%; + --color-neu-200: 76 15% 60%; + --color-neu-100: 76 15% 40%; + --color-neu-50: 77 14% 20%; + --color-neu-0: 75 15% 5%; +} diff --git a/src/app/conf/2023/layout.tsx b/src/app/conf/2023/layout.tsx index 4669949d2c..6b3f04a9db 100644 --- a/src/app/conf/2023/layout.tsx +++ b/src/app/conf/2023/layout.tsx @@ -4,6 +4,7 @@ import { Header } from "../_components/header" import { Footer } from "../_components/footer" import { GraphQLConf, HostedByGraphQLFoundation } from "@/icons" import NextLink from "next/link" +import { OldFontsStyleTag } from "../../fonts/old-fonts" export const metadata = { description: @@ -33,6 +34,7 @@ export default function ConfLayout({ const hover = "#c026d3" return ( <> + diff --git a/src/code/language-support/javascript/server/apollo-server.md b/src/code/language-support/javascript/server/apollo-server.md index d88aa3ef09..ac951b7f41 100644 --- a/src/code/language-support/javascript/server/apollo-server.md +++ b/src/code/language-support/javascript/server/apollo-server.md @@ -17,17 +17,18 @@ Then run `node server.js` with this code in `server.js`: ```js import { ApolloServer } from "@apollo/server" import { startStandaloneServer } from "@apollo/server/standalone" -import { buildSchema } from "graphql" -const schema = buildSchema(` - type Query { - hello: String - } -`) +// The GraphQL schema +const typeDefs = `#graphql + type Query { + hello: String + } +` +// A map of functions which return data for the schema. const resolvers = { Query: { - hello: () => "Hello World!", + hello: () => "world", }, } @@ -37,7 +38,6 @@ const server = new ApolloServer({ }) const { url } = await startStandaloneServer(server) - console.log(`🚀 Server ready at ${url}`) ``` diff --git a/src/code/language-support/php/server/graphql-attribute-schema.md b/src/code/language-support/php/server/graphql-attribute-schema.md new file mode 100644 index 0000000000..f07fe4cfc1 --- /dev/null +++ b/src/code/language-support/php/server/graphql-attribute-schema.md @@ -0,0 +1,111 @@ +--- +name: graphql-attribute-schema +description: Easily build your GraphQL schema for webonyx/graphql-php using PHP attributes instead of large configuration arrays. +url: https://jerowork.github.io/graphql-attribute-schema +github: jerowork/graphql-attribute-schema +--- + +Easily build your GraphQL schema for `webonyx/graphql-php` using PHP attributes instead of large configuration arrays. + +A simple example: + +```php +use Jerowork\GraphqlAttributeSchema\Attribute\Enum; +use Jerowork\GraphqlAttributeSchema\Attribute\Field; +use Jerowork\GraphqlAttributeSchema\Attribute\InputType; +use Jerowork\GraphqlAttributeSchema\Attribute\Mutation; +use Jerowork\GraphqlAttributeSchema\Attribute\Query; +use Jerowork\GraphqlAttributeSchema\Attribute\Type; + +final readonly class CreateUserMutation +{ + #[Mutation] + public function createUser(CreateUserInputType $input): User + { + // Business logic to create a user + } +} + +final readonly class UserQuery +{ + #[Query(description: 'Get a user')] + public function user(int $userid): User + { + // Fetch and return user data + } +} + +#[InputType] +final readonly class CreateUserInputType +{ + public function __construct( + #[Field] + public int $userId, + #[Field] + public string $name, + #[Field(name: 'phoneNumber')] + public ?string $phone, + ) {} +} + +#[Type] +final readonly class User +{ + // Define fields as class properties + public function __construct( + #[Field] + public int $userId, + #[Field] + public string $name, + public ?string $phone, + #[Field(description: 'The status of the user')] + public UserStatusType $status, + ) {} + + // Define fields with methods for additional logic + #[Field] + public function getPhoneNumber(): string + { + return sprintf('+31%s', $this->phone); + } +} + +#[Enum(description: 'The status of the user')] +enum UserStatusType: string +{ + case Created = 'CREATED'; + case Removed = 'REMOVED'; +} +``` + +This will result in the following GraphQL schema: + +```graphql +type Mutation { + createUser(input: CreateUserInput!): User! +} + +type Query { + user(userId: Int!): User! +} + +input CreateUserInput { + userId: Int! + name: String! + phoneNumber: String +} + +type User { + userId: Int! + name: String! + status: UserStatus! + phoneNumber: String +} + +enum UserStatus { + CREATED + REMOVED +} +``` + +Available attributes: `Mutation`, `Query`, `Type`, `InterfaceType`, `InputType`, `Enum`, `EnumValue`, `Field`, `Arg`, `Autowire`, `Scalar`, `Cursor` diff --git a/src/code/services/grafbase.md b/src/code/services/grafbase.md index 78dd9406ea..2444f91ad7 100644 --- a/src/code/services/grafbase.md +++ b/src/code/services/grafbase.md @@ -1,5 +1,5 @@ --- name: Grafbase -description: GraphQL backends made easy. Build your backend declaratively using a schema-first approach. Accelerate development and reduce boilerplate code by leveraging powerful directives and scalars. +description: Grafbase provides secure self-hosted deployment options for GraphQL Federation, unmatched query speed, advanced governance, and unified data access for reliable, enterprise-grade API management. Learn more about scaling GraphQL Federation with [Grafbase](https://grafbase.com). url: https://grafbase.com --- diff --git a/src/code/tools/hive/gateways-supergraphs/hive.md b/src/code/tools/hive/gateways-supergraphs/hive.md index 467c6d4f92..af42b94f1e 100644 --- a/src/code/tools/hive/gateways-supergraphs/hive.md +++ b/src/code/tools/hive/gateways-supergraphs/hive.md @@ -4,3 +4,9 @@ description: Hive Gateway can act as a GraphQL federation gateway or a proxy for url: https://the-guild.dev/graphql/hive github: graphql-hive/gateway --- + +[Hive Gateway](https://the-guild.dev/graphql/hive/docs/gateway) is a fully open-source, MIT-licensed GraphQL router that can act as a [GraphQL Federation](https://the-guild.dev/graphql/hive/federation) gateway, a subgraph or a proxy gateway for any GraphQL API service. + +Hive Gateway provides a flexible, open-source solution tailored to meet the needs of modern GraphQL architectures. + +It supports deployment as a [standalone binary](https://the-guild.dev/graphql/hive/docs/gateway#starting-the-gateway), a [Docker image](https://the-guild.dev/graphql/hive/docs/gateway/deployment/docker), or a [JavaScript package](https://the-guild.dev/graphql/hive/docs/gateway#installation), making it compatible with environments such as [Node.js](https://the-guild.dev/graphql/hive/docs/gateway/deployment/runtimes/nodejs), [Bun](https://the-guild.dev/graphql/hive/docs/gateway/deployment/runtimes/bun), [Deno](https://the-guild.dev/graphql/hive/docs/gateway/deployment/runtimes/deno), [Google Cloud Functions](https://the-guild.dev/graphql/hive/docs/gateway/deployment/serverless/google-cloud-platform), [Azure Functions](https://the-guild.dev/graphql/hive/docs/gateway/deployment/serverless/azure-functions), [AWS Lambda](https://the-guild.dev/graphql/hive/docs/gateway/deployment/serverless/aws-lambda), or [Cloudflare Workers](https://the-guild.dev/graphql/hive/docs/gateway/deployment/serverless/cloudflare-workers). diff --git a/src/github-stats.json b/src/github-stats.json index 71fa63ef3e..0967ef424b 100644 --- a/src/github-stats.json +++ b/src/github-stats.json @@ -1,1274 +1 @@ -{ - "altair-graphql/altair": { - "hasCommitsInLast3Months": false, - "stars": 4981, - "formattedStars": "5k", - "license": "MIT License", - "lastRelease": "2024-03-02T23:05:31Z", - "formattedLastRelease": "3 weeks ago" - }, - "apache/apisix": { - "hasCommitsInLast3Months": false, - "stars": 13572, - "formattedStars": "14k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-25T10:09:53Z", - "formattedLastRelease": "2 days ago" - }, - "apollographql/apollo-studio-community": { - "hasCommitsInLast3Months": false, - "stars": 247, - "formattedStars": "247", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "ChilliCream/hotchocolate": { - "hasCommitsInLast3Months": false, - "stars": 4852, - "formattedStars": "5k", - "license": "MIT License", - "lastRelease": "2024-03-26T20:29:04Z", - "formattedLastRelease": "20 hours ago" - }, - "dgraph-io/dgraph": { - "hasCommitsInLast3Months": false, - "stars": 20002, - "formattedStars": "20k", - "license": "Other", - "lastRelease": "2023-08-17T19:57:12Z", - "formattedLastRelease": "7 months ago" - }, - "yahoo/elide": { - "hasCommitsInLast3Months": false, - "stars": 984, - "formattedStars": "1k", - "license": "Other", - "lastRelease": "2024-03-23T17:37:05Z", - "formattedLastRelease": "3 days ago" - }, - "graphapi-io/resources": { - "hasCommitsInLast3Months": false, - "stars": 1, - "formattedStars": "1", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "hasura/graphql-engine": { - "hasCommitsInLast3Months": false, - "stars": 30748, - "formattedStars": "31k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-24T15:06:36Z", - "formattedLastRelease": "3 days ago" - }, - "Kong/insomnia": { - "hasCommitsInLast3Months": false, - "stars": 32832, - "formattedStars": "33k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-27T13:34:31Z", - "formattedLastRelease": "3 hours ago" - }, - "postmanlabs/postman-app-support": { - "hasCommitsInLast3Months": false, - "stars": 5729, - "formattedStars": "6k", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "prisma/prisma": { - "hasCommitsInLast3Months": false, - "stars": 36814, - "formattedStars": "37k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-12T14:56:01Z", - "formattedLastRelease": "2 weeks ago" - }, - "stepzen-dev/examples": { - "hasCommitsInLast3Months": false, - "stars": 40, - "formattedStars": "40", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "TykTechnologies/tyk": { - "hasCommitsInLast3Months": false, - "stars": 9186, - "formattedStars": "9k", - "license": "Other", - "lastRelease": "2024-03-07T13:28:33Z", - "formattedLastRelease": "2 weeks ago" - }, - "twinlogix/typetta": { - "hasCommitsInLast3Months": false, - "stars": 98, - "formattedStars": "98", - "license": "Apache License 2.0", - "lastRelease": "2023-10-16T07:50:50Z", - "formattedLastRelease": "5 months ago" - }, - "webiny/webiny-js": { - "hasCommitsInLast3Months": false, - "stars": 7071, - "formattedStars": "7k", - "license": "Other", - "lastRelease": "2024-03-12T13:07:17Z", - "formattedLastRelease": "2 weeks ago" - }, - "ballerina-platform/module-ballerina-graphql": { - "hasCommitsInLast3Months": false, - "stars": 144, - "formattedStars": "144", - "license": "Apache License 2.0", - "lastRelease": "2024-02-21T06:14:48Z", - "formattedLastRelease": "1 month ago" - }, - "graphql-dotnet/graphql-client": { - "hasCommitsInLast3Months": false, - "stars": 598, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-03-20T13:07:11Z", - "formattedLastRelease": "1 week ago" - }, - "bkniffler/graphql-net-client": { - "hasCommitsInLast3Months": false, - "stars": 94, - "formattedStars": "94", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "sahb1239/SAHB.GraphQLClient": { - "hasCommitsInLast3Months": false, - "stars": 43, - "formattedStars": "43", - "license": "MIT License", - "lastRelease": "2020-05-17T10:50:58Z", - "formattedLastRelease": "3 years ago" - }, - "byme8/ZeroQL": { - "hasCommitsInLast3Months": false, - "stars": 238, - "formattedStars": "238", - "license": "MIT License", - "lastRelease": "2024-02-19T19:05:47Z", - "formattedLastRelease": "1 month ago" - }, - "EntityGraphQL/EntityGraphQL": { - "hasCommitsInLast3Months": false, - "stars": 376, - "formattedStars": "376", - "license": "MIT License", - "lastRelease": "2024-03-19T16:00:01Z", - "formattedLastRelease": "1 week ago" - }, - "graphql-dotnet/graphql-dotnet": { - "hasCommitsInLast3Months": false, - "stars": 5726, - "formattedStars": "6k", - "license": "MIT License", - "lastRelease": "2024-02-06T15:23:47Z", - "formattedLastRelease": "1 month ago" - }, - "chkimes/graphql-net": { - "hasCommitsInLast3Months": false, - "stars": 889, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "rivantsov/ngraphql": { - "hasCommitsInLast3Months": false, - "stars": 37, - "formattedStars": "37", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "graphql/libgraphqlparser": { - "hasCommitsInLast3Months": false, - "stars": 1055, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2017-10-16T21:47:42Z", - "formattedLastRelease": "6 years ago" - }, - "oliyh/re-graph": { - "hasCommitsInLast3Months": false, - "stars": 455, - "formattedStars": "455", - "license": "Unknown", - "lastRelease": "2022-07-20T09:24:02Z", - "formattedLastRelease": "1 year ago" - }, - "alumbra/alumbra": { - "hasCommitsInLast3Months": false, - "stars": 148, - "formattedStars": "148", - "license": "MIT License", - "lastRelease": "2017-06-12T12:14:25Z", - "formattedLastRelease": "6 years ago" - }, - "tendant/graphql-clj": { - "hasCommitsInLast3Months": false, - "stars": 282, - "formattedStars": "282", - "license": "Eclipse Public License 1.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "walmartlabs/lacinia": { - "hasCommitsInLast3Months": false, - "stars": 1798, - "formattedStars": "2k", - "license": "Other", - "lastRelease": "", - "formattedLastRelease": "" - }, - "burner/graphqld": { - "hasCommitsInLast3Months": false, - "stars": 34, - "formattedStars": "34", - "license": "GNU Lesser General Public License v3.0", - "lastRelease": "2023-12-15T16:28:51Z", - "formattedLastRelease": "3 months ago" - }, - "annkissam/common_graphql_client": { - "hasCommitsInLast3Months": false, - "stars": 43, - "formattedStars": "43", - "license": "MIT License", - "lastRelease": "2020-05-05T16:48:50Z", - "formattedLastRelease": "3 years ago" - }, - "uesteibar/neuron": { - "hasCommitsInLast3Months": false, - "stars": 322, - "formattedStars": "322", - "license": "Other", - "lastRelease": "", - "formattedLastRelease": "" - }, - "absinthe-graphql/absinthe": { - "hasCommitsInLast3Months": false, - "stars": 4211, - "formattedStars": "4k", - "license": "Other", - "lastRelease": "2021-09-28T21:41:45Z", - "formattedLastRelease": "2 years ago" - }, - "graphql-elixir/graphql": { - "hasCommitsInLast3Months": false, - "stars": 859, - "formattedStars": "1k", - "license": "Other", - "lastRelease": "2016-09-09T04:49:46Z", - "formattedLastRelease": "7 years ago" - }, - "dillonkearns/elm-graphql": { - "hasCommitsInLast3Months": false, - "stars": 775, - "formattedStars": "1k", - "license": "BSD 3-Clause \"New\" or \"Revised\" License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "jlouis/graphql-erlang": { - "hasCommitsInLast3Months": false, - "stars": 314, - "formattedStars": "314", - "license": "Other", - "lastRelease": "2018-06-22T12:35:43Z", - "formattedLastRelease": "5 years ago" - }, - "gql-dart/ferry": { - "hasCommitsInLast3Months": false, - "stars": 575, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "zino-app/graphql-flutter": { - "hasCommitsInLast3Months": false, - "stars": 3212, - "formattedStars": "3k", - "license": "MIT License", - "lastRelease": "2023-12-28T21:29:30Z", - "formattedLastRelease": "2 months ago" - }, - "Khan/genqlient": { - "hasCommitsInLast3Months": false, - "stars": 970, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-03-05T07:00:55Z", - "formattedLastRelease": "3 weeks ago" - }, - "hasura/go-graphql-client": { - "hasCommitsInLast3Months": false, - "stars": 366, - "formattedStars": "366", - "license": "MIT License", - "lastRelease": "2024-03-04T16:49:07Z", - "formattedLastRelease": "3 weeks ago" - }, - "shurcooL/graphql": { - "hasCommitsInLast3Months": false, - "stars": 684, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "machinebox/graphql": { - "hasCommitsInLast3Months": false, - "stars": 919, - "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "2018-05-31T14:28:32Z", - "formattedLastRelease": "5 years ago" - }, - "99designs/gqlgen": { - "hasCommitsInLast3Months": false, - "stars": 9560, - "formattedStars": "10k", - "license": "MIT License", - "lastRelease": "2024-03-11T23:13:45Z", - "formattedLastRelease": "2 weeks ago" - }, - "andrewwphillips/eggql": { - "hasCommitsInLast3Months": false, - "stars": 32, - "formattedStars": "32", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "appointy/jaal": { - "hasCommitsInLast3Months": false, - "stars": 76, - "formattedStars": "76", - "license": "MIT License", - "lastRelease": "2020-04-18T08:53:19Z", - "formattedLastRelease": "3 years ago" - }, - "graph-gophers/graphql-go": { - "hasCommitsInLast3Months": false, - "stars": 4588, - "formattedStars": "5k", - "license": "BSD 2-Clause \"Simplified\" License", - "lastRelease": "2022-12-19T10:05:46Z", - "formattedLastRelease": "1 year ago" - }, - "graphql-go/graphql": { - "hasCommitsInLast3Months": false, - "stars": 9677, - "formattedStars": "10k", - "license": "MIT License", - "lastRelease": "2023-04-10T18:20:23Z", - "formattedLastRelease": "11 months ago" - }, - "graphql-go/relay": { - "hasCommitsInLast3Months": false, - "stars": 422, - "formattedStars": "422", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "samsarahq/thunder": { - "hasCommitsInLast3Months": false, - "stars": 1588, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "wundergraph/graphql-go-tools": { - "hasCommitsInLast3Months": false, - "stars": 628, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-10-12T13:16:31Z", - "formattedLastRelease": "5 months ago" - }, - "dosco/graphjin": { - "hasCommitsInLast3Months": false, - "stars": 2828, - "formattedStars": "3k", - "license": "Apache License 2.0", - "lastRelease": "2023-12-14T23:23:03Z", - "formattedLastRelease": "3 months ago" - }, - "grails/gorm-graphql": { - "hasCommitsInLast3Months": false, - "stars": 80, - "formattedStars": "80", - "license": "Apache License 2.0", - "lastRelease": "2023-12-08T10:48:05Z", - "formattedLastRelease": "3 months ago" - }, - "grooviter/gql": { - "hasCommitsInLast3Months": false, - "stars": 47, - "formattedStars": "47", - "license": "Apache License 2.0", - "lastRelease": "2022-12-07T00:50:33Z", - "formattedLastRelease": "1 year ago" - }, - "morpheusgraphql/morpheus-graphql": { - "hasCommitsInLast3Months": false, - "stars": 400, - "formattedStars": "400", - "license": "MIT License", - "lastRelease": "2023-04-27T20:20:22Z", - "formattedLastRelease": "11 months ago" - }, - "jasonsychau/graphql-w-persistent": { - "hasCommitsInLast3Months": false, - "stars": 10, - "formattedStars": "10", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "higherkindness/mu-haskell": { - "hasCommitsInLast3Months": false, - "stars": 325, - "formattedStars": "325", - "license": "Apache License 2.0", - "lastRelease": "2021-01-11T11:19:38Z", - "formattedLastRelease": "3 years ago" - }, - "apollographql/apollo-kotlin": { - "hasCommitsInLast3Months": false, - "stars": 3655, - "formattedStars": "4k", - "license": "MIT License", - "lastRelease": "2024-03-20T17:46:54Z", - "formattedLastRelease": "6 days ago" - }, - "ExpediaGroup/graphql-kotlin": { - "hasCommitsInLast3Months": false, - "stars": 1709, - "formattedStars": "2k", - "license": "Apache License 2.0", - "lastRelease": "2024-01-25T02:45:25Z", - "formattedLastRelease": "2 months ago" - }, - "americanexpress/nodes": { - "hasCommitsInLast3Months": false, - "stars": 305, - "formattedStars": "305", - "license": "Apache License 2.0", - "lastRelease": "2019-07-13T22:47:01Z", - "formattedLastRelease": "4 years ago" - }, - "graphql-java-generator/graphql-gradle-plugin-project": { - "hasCommitsInLast3Months": false, - "stars": 51, - "formattedStars": "51", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "graphql-calculator/graphql-calculator": { - "hasCommitsInLast3Months": false, - "stars": 104, - "formattedStars": "104", - "license": "Apache License 2.0", - "lastRelease": "2021-09-03T01:56:25Z", - "formattedLastRelease": "2 years ago" - }, - "graphql-java-kickstart/graphql-spring-boot": { - "hasCommitsInLast3Months": false, - "stars": 1502, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2023-12-07T11:07:47Z", - "formattedLastRelease": "3 months ago" - }, - "graphql-java/graphql-java": { - "hasCommitsInLast3Months": false, - "stars": 6020, - "formattedStars": "6k", - "license": "MIT License", - "lastRelease": "2024-03-26T05:23:07Z", - "formattedLastRelease": "1 day ago" - }, - "babyfish-ct/jimmer": { - "hasCommitsInLast3Months": false, - "stars": 615, - "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-24T23:34:18Z", - "formattedLastRelease": "2 days ago" - }, - "aPureBase/KGraphQL": { - "hasCommitsInLast3Months": false, - "stars": 292, - "formattedStars": "292", - "license": "MIT License", - "lastRelease": "2023-01-27T10:09:55Z", - "formattedLastRelease": "1 year ago" - }, - "eclipse/microprofile-graphql": { - "hasCommitsInLast3Months": false, - "stars": 94, - "formattedStars": "94", - "license": "Apache License 2.0", - "lastRelease": "2022-03-21T18:26:51Z", - "formattedLastRelease": "2 years ago" - }, - "netflix/dgs-framework": { - "hasCommitsInLast3Months": false, - "stars": 2962, - "formattedStars": "3k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-19T16:41:26Z", - "formattedLastRelease": "1 week ago" - }, - "spring-projects/spring-graphql": { - "hasCommitsInLast3Months": false, - "stars": 1479, - "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "2024-02-21T10:11:39Z", - "formattedLastRelease": "1 month ago" - }, - "neomatrixcode/Diana.jl": { - "hasCommitsInLast3Months": false, - "stars": 112, - "formattedStars": "112", - "license": "MIT License", - "lastRelease": "2022-08-16T03:22:22Z", - "formattedLastRelease": "1 year ago" - }, - "DeloitteDigitalAPAC/GraphQLClient.jl": { - "hasCommitsInLast3Months": false, - "stars": 46, - "formattedStars": "46", - "license": "Other", - "lastRelease": "2022-10-26T16:48:16Z", - "formattedLastRelease": "1 year ago" - }, - "apollographql/apollo-client": { - "hasCommitsInLast3Months": false, - "stars": 19177, - "formattedStars": "19k", - "license": "MIT License", - "lastRelease": "2024-03-22T19:44:35Z", - "formattedLastRelease": "4 days ago" - }, - "aws-amplify/amplify-js": { - "hasCommitsInLast3Months": false, - "stars": 9359, - "formattedStars": "9k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-26T13:44:09Z", - "formattedLastRelease": "1 day ago" - }, - "Houfeng/gq-loader": { - "hasCommitsInLast3Months": false, - "stars": 59, - "formattedStars": "59", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "grafoojs/grafoo": { - "hasCommitsInLast3Months": false, - "stars": 274, - "formattedStars": "274", - "license": "MIT License", - "lastRelease": "2018-06-20T15:21:00Z", - "formattedLastRelease": "5 years ago" - }, - "badbatch/graphql-box": { - "hasCommitsInLast3Months": false, - "stars": 23, - "formattedStars": "23", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "nearform/graphql-hooks": { - "hasCommitsInLast3Months": false, - "stars": 1866, - "formattedStars": "2k", - "license": "Other", - "lastRelease": "2024-01-19T16:50:14Z", - "formattedLastRelease": "2 months ago" - }, - "graphql/graphql-http": { - "hasCommitsInLast3Months": false, - "stars": 274, - "formattedStars": "274", - "license": "MIT License", - "lastRelease": "2023-08-28T14:50:20Z", - "formattedLastRelease": "6 months ago" - }, - "jasonkuhrt/graphql-request": { - "hasCommitsInLast3Months": false, - "stars": 5623, - "formattedStars": "6k", - "license": "MIT License", - "lastRelease": "2020-05-29T13:00:56Z", - "formattedLastRelease": "3 years ago" - }, - "enisdenjo/graphql-sse": { - "hasCommitsInLast3Months": false, - "stars": 365, - "formattedStars": "365", - "license": "MIT License", - "lastRelease": "2023-12-20T12:22:07Z", - "formattedLastRelease": "3 months ago" - }, - "babyfish-ct/graphql-ts-client": { - "hasCommitsInLast3Months": false, - "stars": 142, - "formattedStars": "142", - "license": "MIT License", - "lastRelease": "2023-12-14T03:06:21Z", - "formattedLastRelease": "3 months ago" - }, - "enisdenjo/graphql-ws": { - "hasCommitsInLast3Months": false, - "stars": 1642, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2024-02-12T17:57:24Z", - "formattedLastRelease": "1 month ago" - }, - "hasura/graphqurl": { - "hasCommitsInLast3Months": false, - "stars": 3300, - "formattedStars": "3k", - "license": "Apache License 2.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "kadirahq/lokka": { - "hasCommitsInLast3Months": false, - "stars": 1531, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "choojs/nanographql": { - "hasCommitsInLast3Months": false, - "stars": 422, - "formattedStars": "422", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "facebook/relay": { - "hasCommitsInLast3Months": false, - "stars": 18149, - "formattedStars": "18k", - "license": "MIT License", - "lastRelease": "2024-01-23T16:49:06Z", - "formattedLastRelease": "2 months ago" - }, - "FormidableLabs/urql": { - "hasCommitsInLast3Months": false, - "stars": 8450, - "formattedStars": "8k", - "license": "MIT License", - "lastRelease": "2024-03-27T12:10:54Z", - "formattedLastRelease": "5 hours ago" - }, - "apollographql/apollo-server": { - "hasCommitsInLast3Months": false, - "stars": 13638, - "formattedStars": "14k", - "license": "MIT License", - "lastRelease": "2024-03-22T19:40:52Z", - "formattedLastRelease": "4 days ago" - }, - "graphql/graphql-js": { - "hasCommitsInLast3Months": false, - "stars": 19896, - "formattedStars": "20k", - "license": "MIT License", - "lastRelease": "2023-09-19T07:27:40Z", - "formattedLastRelease": "6 months ago" - }, - "dotansimha/graphql-yoga": { - "hasCommitsInLast3Months": false, - "stars": 7974, - "formattedStars": "8k", - "license": "MIT License", - "lastRelease": "2024-03-13T14:22:21Z", - "formattedLastRelease": "2 weeks ago" - }, - "mercurius-js/mercurius": { - "hasCommitsInLast3Months": false, - "stars": 2294, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2024-03-19T10:55:16Z", - "formattedLastRelease": "1 week ago" - }, - "networkimprov/brangr": { - "hasCommitsInLast3Months": false, - "stars": 1, - "formattedStars": "1", - "license": "Mozilla Public License 2.0", - "lastRelease": "2023-06-02T09:20:18Z", - "formattedLastRelease": "9 months ago" - }, - "hayes/giraphql": { - "hasCommitsInLast3Months": false, - "stars": 2211, - "formattedStars": "2k", - "license": "ISC License", - "lastRelease": "2024-03-05T19:54:00Z", - "formattedLastRelease": "3 weeks ago" - }, - "graphql/graphiql": { - "hasCommitsInLast3Months": false, - "stars": 15615, - "formattedStars": "16k", - "license": "MIT License", - "lastRelease": "2024-03-01T18:28:05Z", - "formattedLastRelease": "3 weeks ago" - }, - "Urigo/graphql-cli": { - "hasCommitsInLast3Months": false, - "stars": 1983, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2020-10-07T12:54:45Z", - "formattedLastRelease": "3 years ago" - }, - "dotansimha/graphql-code-generator": { - "hasCommitsInLast3Months": false, - "stars": 10596, - "formattedStars": "11k", - "license": "MIT License", - "lastRelease": "2024-03-27T11:16:28Z", - "formattedLastRelease": "6 hours ago" - }, - "kamilkisiela/graphql-config": { - "hasCommitsInLast3Months": false, - "stars": 1144, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-10-08T22:16:50Z", - "formattedLastRelease": "5 months ago" - }, - "dimaMachina/graphql-eslint/": { - "hasCommitsInLast3Months": false, - "stars": 756, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-08-29T17:53:28Z", - "formattedLastRelease": "6 months ago" - }, - "kamilkisiela/graphql-inspector": { - "hasCommitsInLast3Months": false, - "stars": 1600, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2023-11-29T13:09:10Z", - "formattedLastRelease": "3 months ago" - }, - "graphql/graphql-language-service": { - "hasCommitsInLast3Months": false, - "stars": 421, - "formattedStars": "421", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "n1ru4l/graphql-live-query": { - "hasCommitsInLast3Months": false, - "stars": 433, - "formattedStars": "433", - "license": "MIT License", - "lastRelease": "2022-07-29T09:27:53Z", - "formattedLastRelease": "1 year ago" - }, - "Urigo/graphql-mesh": { - "hasCommitsInLast3Months": false, - "stars": 3149, - "formattedStars": "3k", - "license": "MIT License", - "lastRelease": "2024-03-27T12:45:28Z", - "formattedLastRelease": "4 hours ago" - }, - "maticzav/graphql-middleware": { - "hasCommitsInLast3Months": false, - "stars": 1128, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-07-07T16:38:02Z", - "formattedLastRelease": "8 months ago" - }, - "Urigo/graphql-modules": { - "hasCommitsInLast3Months": false, - "stars": 1286, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-11-03T08:01:19Z", - "formattedLastRelease": "4 months ago" - }, - "Urigo/graphql-scalars": { - "hasCommitsInLast3Months": false, - "stars": 1830, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2024-03-18T14:47:27Z", - "formattedLastRelease": "1 week ago" - }, - "maticzav/graphql-shield": { - "hasCommitsInLast3Months": false, - "stars": 3507, - "formattedStars": "4k", - "license": "MIT License", - "lastRelease": "2022-11-22T19:08:37Z", - "formattedLastRelease": "1 year ago" - }, - "ardatan/graphql-tools": { - "hasCommitsInLast3Months": false, - "stars": 5272, - "formattedStars": "5k", - "license": "MIT License", - "lastRelease": "2024-03-23T13:50:38Z", - "formattedLastRelease": "4 days ago" - }, - "anvilco/graphql-introspection-tools": { - "hasCommitsInLast3Months": false, - "stars": 30, - "formattedStars": "30", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "graphile/postgraphile": { - "hasCommitsInLast3Months": false, - "stars": 12384, - "formattedStars": "12k", - "license": "Other", - "lastRelease": "2023-10-05T16:27:00Z", - "formattedLastRelease": "5 months ago" - }, - "Urigo/SOFA": { - "hasCommitsInLast3Months": false, - "stars": 1041, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-12-27T11:00:49Z", - "formattedLastRelease": "3 months ago" - }, - "anvilco/spectaql": { - "hasCommitsInLast3Months": false, - "stars": 1031, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "andreas/ocaml-graphql-server": { - "hasCommitsInLast3Months": false, - "stars": 623, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2022-07-08T16:26:45Z", - "formattedLastRelease": "1 year ago" - }, - "graphql-perl/graphql-perl": { - "hasCommitsInLast3Months": false, - "stars": 70, - "formattedStars": "70", - "license": "Unknown", - "lastRelease": "", - "formattedLastRelease": "" - }, - "api-platform/api-platform": { - "hasCommitsInLast3Months": false, - "stars": 8264, - "formattedStars": "8k", - "license": "MIT License", - "lastRelease": "2024-03-26T07:56:13Z", - "formattedLastRelease": "1 day ago" - }, - "GatoGraphQL/GatoGraphQL": { - "hasCommitsInLast3Months": false, - "stars": 349, - "formattedStars": "349", - "license": "GNU General Public License v2.0", - "lastRelease": "2024-03-27T06:49:09Z", - "formattedLastRelease": "10 hours ago" - }, - "infinityloop-dev/graphpinator": { - "hasCommitsInLast3Months": false, - "stars": 39, - "formattedStars": "39", - "license": "MIT License", - "lastRelease": "2023-11-13T10:08:26Z", - "formattedLastRelease": "4 months ago" - }, - "webonyx/graphql-php": { - "hasCommitsInLast3Months": false, - "stars": 4598, - "formattedStars": "5k", - "license": "MIT License", - "lastRelease": "2024-03-11T10:21:35Z", - "formattedLastRelease": "2 weeks ago" - }, - "ivome/graphql-relay-php": { - "hasCommitsInLast3Months": false, - "stars": 271, - "formattedStars": "271", - "license": "BSD 3-Clause \"New\" or \"Revised\" License", - "lastRelease": "2021-04-24T19:40:30Z", - "formattedLastRelease": "2 years ago" - }, - "overblog/GraphQLBundle": { - "hasCommitsInLast3Months": false, - "stars": 776, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-03-11T08:38:27Z", - "formattedLastRelease": "2 weeks ago" - }, - "thecodingmachine/graphqlite": { - "hasCommitsInLast3Months": false, - "stars": 551, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-03-20T05:52:53Z", - "formattedLastRelease": "1 week ago" - }, - "nuwave/lighthouse": { - "hasCommitsInLast3Months": false, - "stars": 3308, - "formattedStars": "3k", - "license": "MIT License", - "lastRelease": "2024-03-11T10:30:48Z", - "formattedLastRelease": "2 weeks ago" - }, - "railt/railt": { - "hasCommitsInLast3Months": false, - "stars": 360, - "formattedStars": "360", - "license": "MIT License", - "lastRelease": "2019-03-01T15:20:44Z", - "formattedLastRelease": "5 years ago" - }, - "kepawni/serge": { - "hasCommitsInLast3Months": false, - "stars": 5, - "formattedStars": "5", - "license": "GNU General Public License v3.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "leocavalcante/siler": { - "hasCommitsInLast3Months": false, - "stars": 1120, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2021-01-27T19:41:57Z", - "formattedLastRelease": "3 years ago" - }, - "wp-graphql/wp-graphql": { - "hasCommitsInLast3Months": false, - "stars": 3592, - "formattedStars": "4k", - "license": "GNU General Public License v3.0", - "lastRelease": "2024-03-14T22:13:00Z", - "formattedLastRelease": "1 week ago" - }, - "mirumee/ariadne-codegen": { - "hasCommitsInLast3Months": false, - "stars": 195, - "formattedStars": "195", - "license": "BSD 3-Clause \"New\" or \"Revised\" License", - "lastRelease": "2024-03-04T15:58:27Z", - "formattedLastRelease": "3 weeks ago" - }, - "graphql-python/gql": { - "hasCommitsInLast3Months": false, - "stars": 1449, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-02-08T22:50:50Z", - "formattedLastRelease": "1 month ago" - }, - "denisart/graphql-query": { - "hasCommitsInLast3Months": false, - "stars": 45, - "formattedStars": "45", - "license": "MIT License", - "lastRelease": "2024-02-19T13:45:58Z", - "formattedLastRelease": "1 month ago" - }, - "prisma-labs/python-graphql-client": { - "hasCommitsInLast3Months": false, - "stars": 155, - "formattedStars": "155", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "qlient-org/python-qlient": { - "hasCommitsInLast3Months": false, - "stars": 45, - "formattedStars": "45", - "license": "MIT License", - "lastRelease": "2022-07-29T16:10:08Z", - "formattedLastRelease": "1 year ago" - }, - "profusion/sgqlc": { - "hasCommitsInLast3Months": false, - "stars": 492, - "formattedStars": "492", - "license": "ISC License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "mirumee/ariadne": { - "hasCommitsInLast3Months": false, - "stars": 2130, - "formattedStars": "2k", - "license": "BSD 3-Clause \"New\" or \"Revised\" License", - "lastRelease": "2024-03-18T10:27:12Z", - "formattedLastRelease": "1 week ago" - }, - "yefeza/django-graphbox": { - "hasCommitsInLast3Months": false, - "stars": 9, - "formattedStars": "9", - "license": "MIT License", - "lastRelease": "2024-03-23T21:41:41Z", - "formattedLastRelease": "3 days ago" - }, - "graphql-python/graphene": { - "hasCommitsInLast3Months": false, - "stars": 7953, - "formattedStars": "8k", - "license": "MIT License", - "lastRelease": "2023-07-26T06:47:55Z", - "formattedLastRelease": "8 months ago" - }, - "strawberry-graphql/strawberry": { - "hasCommitsInLast3Months": false, - "stars": 3721, - "formattedStars": "4k", - "license": "MIT License", - "lastRelease": "2024-03-27T13:04:35Z", - "formattedLastRelease": "4 hours ago" - }, - "tartiflette/tartiflette": { - "hasCommitsInLast3Months": false, - "stars": 852, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2021-11-15T11:05:03Z", - "formattedLastRelease": "2 years ago" - }, - "ropensci/ghql": { - "hasCommitsInLast3Months": false, - "stars": 141, - "formattedStars": "141", - "license": "Other", - "lastRelease": "2020-02-24T18:15:36Z", - "formattedLastRelease": "4 years ago" - }, - "ohler55/agoo": { - "hasCommitsInLast3Months": false, - "stars": 882, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "rmosolgo/graphql-ruby": { - "hasCommitsInLast3Months": false, - "stars": 5323, - "formattedStars": "5k", - "license": "MIT License", - "lastRelease": "2021-02-12T12:11:53Z", - "formattedLastRelease": "3 years ago" - }, - "virtualshield/rails-graphql": { - "hasCommitsInLast3Months": false, - "stars": 165, - "formattedStars": "165", - "license": "MIT License", - "lastRelease": "2024-02-03T08:44:59Z", - "formattedLastRelease": "1 month ago" - }, - "obmarg/cynic": { - "hasCommitsInLast3Months": false, - "stars": 335, - "formattedStars": "335", - "license": "Mozilla Public License 2.0", - "lastRelease": "2024-03-25T15:31:57Z", - "formattedLastRelease": "2 days ago" - }, - "arthurkhlghatyan/gql-client-rs": { - "hasCommitsInLast3Months": false, - "stars": 47, - "formattedStars": "47", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "async-graphql/async-graphql": { - "hasCommitsInLast3Months": false, - "stars": 3196, - "formattedStars": "3k", - "license": "Apache License 2.0", - "lastRelease": "2022-11-28T06:30:57Z", - "formattedLastRelease": "1 year ago" - }, - "graphql-rust/juniper": { - "hasCommitsInLast3Months": false, - "stars": 5513, - "formattedStars": "6k", - "license": "Other", - "lastRelease": "2024-03-20T20:40:22Z", - "formattedLastRelease": "6 days ago" - }, - "ghostdogpr/caliban": { - "hasCommitsInLast3Months": false, - "stars": 930, - "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-03T01:02:04Z", - "formattedLastRelease": "3 weeks ago" - }, - "sangria-graphql/sangria": { - "hasCommitsInLast3Months": false, - "stars": 1963, - "formattedStars": "2k", - "license": "Apache License 2.0", - "lastRelease": "2024-02-01T10:01:14Z", - "formattedLastRelease": "1 month ago" - }, - "apollographql/apollo-ios": { - "hasCommitsInLast3Months": false, - "stars": 3814, - "formattedStars": "4k", - "license": "MIT License", - "lastRelease": "2024-03-22T20:36:20Z", - "formattedLastRelease": "4 days ago" - }, - "nerdsupremacist/Graphaello": { - "hasCommitsInLast3Months": false, - "stars": 494, - "formattedStars": "494", - "license": "MIT License", - "lastRelease": "2021-12-19T22:21:30Z", - "formattedLastRelease": "2 years ago" - }, - "funcompany/graphql-ios": { - "hasCommitsInLast3Months": false, - "stars": 62, - "formattedStars": "62", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "relatedcode/GraphQLite": { - "hasCommitsInLast3Months": false, - "stars": 5, - "formattedStars": "5", - "license": "MIT License", - "lastRelease": "2023-09-25T08:40:36Z", - "formattedLastRelease": "6 months ago" - }, - "maticzav/swift-graphql": { - "hasCommitsInLast3Months": false, - "stars": 588, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2024-01-14T13:56:07Z", - "formattedLastRelease": "2 months ago" - }, - "GraphQLSwift/Graphiti": { - "hasCommitsInLast3Months": false, - "stars": 522, - "formattedStars": "1k", - "license": "MIT License", - "lastRelease": "2023-11-15T02:54:16Z", - "formattedLastRelease": "4 months ago" - }, - "nerdsupremacist/GraphZahl": { - "hasCommitsInLast3Months": false, - "stars": 143, - "formattedStars": "143", - "license": "MIT License", - "lastRelease": "2021-05-17T12:51:10Z", - "formattedLastRelease": "2 years ago" - }, - "eerimoq/gqt": { - "hasCommitsInLast3Months": false, - "stars": 455, - "formattedStars": "455", - "license": "MIT License", - "lastRelease": "", - "formattedLastRelease": "" - }, - "Escape-Technologies/graphql-armor": { - "hasCommitsInLast3Months": false, - "stars": 455, - "formattedStars": "455", - "license": "MIT License", - "lastRelease": "2023-12-20T13:32:16Z", - "formattedLastRelease": "3 months ago" - }, - "microcks/microcks": { - "hasCommitsInLast3Months": false, - "stars": 1158, - "formattedStars": "1k", - "license": "Apache License 2.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "schemathesis/schemathesis": { - "hasCommitsInLast3Months": false, - "stars": 2058, - "formattedStars": "2k", - "license": "MIT License", - "lastRelease": "2024-03-21T22:25:47Z", - "formattedLastRelease": "5 days ago" - }, - "glideapps/quicktype": { - "hasCommitsInLast3Months": false, - "stars": 11378, - "formattedStars": "11k", - "license": "Apache License 2.0", - "lastRelease": "", - "formattedLastRelease": "" - }, - "wundergraph/wundergraph": { - "hasCommitsInLast3Months": false, - "stars": 2152, - "formattedStars": "2k", - "license": "Apache License 2.0", - "lastRelease": "2024-03-08T09:27:40Z", - "formattedLastRelease": "2 weeks ago" - }, - "ldebruijn/graphql-protect": { - "hasCommitsInLast3Months": true, - "stars": 24, - "formattedStars": "24", - "license": "MIT", - "lastRelease": "2024-08-28T11:28:00Z", - "formattedLastRelease": "2 weeks ago" - } -} +{} diff --git a/src/globals.css b/src/globals.css index fbaf495fe1..efca847c5b 100644 --- a/src/globals.css +++ b/src/globals.css @@ -148,7 +148,7 @@ div[id^="headlessui-menu-items"] { } ::selection { - @apply bg-primary/50 dark:bg-primary; + @apply bg-primary/50 dark:bg-primary/50; } @media (prefers-color-scheme: dark) { @@ -503,3 +503,24 @@ div[id^="headlessui-menu-items"] { @apply text-xl; @apply dark:border-neutral-700/80; } + +.gql-focus-visible, +.gql-all-anchors-focusable a { + @apply focus-visible:outline focus-visible:outline-[3px] focus-visible:outline-offset-[5px] focus-visible:outline-neu-900; +} + +.gql-conf-container { + @apply mx-auto w-full max-w-[120rem]; +} + +.gql-conf-section { + @apply px-4 py-8 lg:px-12 xl:gap-x-24 xl:px-24 3xl:px-[240px]; +} + +.gql-conf-navbar-strip { + @apply relative [contain:paint] before:sticky before:top-0 before:z-[9] before:-mt-[var(--navbar-h)] before:block before:h-[var(--navbar-h)] before:w-full before:content-['']; +} + +:root { + --navbar-h: 70px; +} diff --git a/src/pages/blog/2025-02-05-welcome-tsc-members-2025.md b/src/pages/blog/2025-02-05-welcome-tsc-members-2025.md new file mode 100644 index 0000000000..13e9536c47 --- /dev/null +++ b/src/pages/blog/2025-02-05-welcome-tsc-members-2025.md @@ -0,0 +1,36 @@ +--- +title: "Welcoming New TSC Members" +tags: ["foundation"] +date: 2025-02-05 +byline: Lee Byron +--- + +The GraphQL Technical Steering Committee is the body responsible for the technical oversight of all our open source projects and management of our open source community. Every year we vote on self-nominees to rotate up to half of TSC members, and we've just concluded the most recent vote. + +### Our new TSC elections... + +I’m excited to share that we have elected two new members to the GraphQL Technical Steering Committee (TSC), [Martin Bonnin](https://github.com/martinbonnin) and [Pascal Senn](https://github.com/PascalSenn), technical leads at Apollo and ChilliCream respectively. They have been consistent contributors to the GraphQL open source project over the last few years and I'm thrilled to have their help in and commitment to guiding and advancing the GraphQL technical project and broader ecosystem. + +In addition, we also re-elected three existing members, [Kewei Qu](https://github.com/Keweiqu) a technical lead at Meta working on the original GraphQL deployment, [Rob Richard](https://github.com/robrichard) an engineer at 1stDibs and the lead of the Streaming GraphQL project, and [Uri Goldshtein](https://github.com/urigo) founder of The Guild. These all join our existing [TSC members](https://github.com/orgs/graphql/teams/tsc/members). + +### Open working groups and the role of the TSC + +GraphQL is an open project. All are welcome to join our [working group](https://github.com/graphql/graphql-wg/) meetings, champion proposals for project-wide improvements, or contribute directly across our open source projects. + +It has been critical to keep access to these working groups open, but it does mean a rotating cast of contributors over time. The primary role of the TSC is to provide continuity as the stewards of this group and our processes, and co-owners of our technical projects. + +While the TSC is a closed group, our focus is always on strengthening the work that happens in our open Working Group meetings—that is where technical work moves forward. + +### Our processes + +To learn more about the TSC and how we work, check out these resources: + +- **[2025 TSC Elections](https://github.com/graphql/graphql-wg/issues/1612)** — we use Github issues for most things across the Working Group and TSC, and this one tracked the TSC election itself. Anyone could self-nominate via a Google Form, and we held a vote via OpaVote. +- **[TSC Charter](https://github.com/graphql/graphql-wg/blob/main/GraphQL-TSC.md)** — this lists out in detail how the TSC is governed, which contains more detail about when and how we take votes, and what we're accountable for. +- **[GraphQL Working Group](https://github.com/graphql/graphql-wg/)** — this is where we organize meetings and contribution across the Working Group, where you'll find past and upcoming agendas and can join an upcoming meeting simply by adding yourself to the next agenda file in a PR. + +I'm beyond lucky to get to work with such a talented group of volunteers both directly on the TSC and across the GraphQL community. + +Welcome, Martin and Pascal! + +— Lee diff --git a/src/pages/blog/2025-02-11-how-to-write-a-successful-conference-proposal.mdx b/src/pages/blog/2025-02-11-how-to-write-a-successful-conference-proposal.mdx new file mode 100644 index 0000000000..960b23b35e --- /dev/null +++ b/src/pages/blog/2025-02-11-how-to-write-a-successful-conference-proposal.mdx @@ -0,0 +1,140 @@ +--- +title: "How to write a successful conference proposal" +tags: ["blog"] +date: 2025-02-11 +byline: Donna Zhou +--- + +By the end of this blog, you'll know: + +* how to write a conference proposal, and +* how to maximise your chance of getting selected to speak + +Speaking at a conference is a goal you can achieve now. You don't have to wait until you've "made it" as a principal engineer. + +I'm going to share with you what I've learned from speaking at the [GraphQL Conference](https://graphql.org/conf/2023/sessions/81daf0dd0b26efdc784ba0a530e54a68/) and how I maximised my chances of getting selected. I'm going to share the full text of my successful conference proposal so you can see how achievable this is. I will also share advice from [Benjie](https://github.com/benjie), a GraphQL Conference proposal reviewer and member of the Technical Steering Committee. + +By this end of this blog, you will have the skills and confidence to write your own successful conference proposal. + +## Why you should speak at a conference +Speaking at conferences is a great way to share knowledge and a fantastic opportunity to meet and learn from your peers. The GraphQL Conference is a fantastic way to connect with the community in person. + +Although it is not the primary motivation, speaking at a conference helps you stand out as an engineer. It demonstrates that you are an expert on the topic. + +## You are already enough +Many developers want to speak at a conference, yet I'm sure the next thought most people have is "but I'm not senior or good enough to do that!" + +You don't need to wait until you are a big deal principal engineer to give a conference talk. At any stage of your career, you have valuable information to share. I'm sure you have already achieved something worth sharing in a conference talk. + +In this blog I will explain how to take the experiences you already have, and present it as a winning conference proposal. **You are already enough!** + +## Selecting conference talk ideas +You will maximise your chance of getting selected if you choose a topic **that more engineers are interested in**. + +Before I became a software engineer, I was a stand-up comedian. When making jokes is your job, you need a systematic way to generate many ideas (jokes) and test them with audiences. You can use the same approach for selecting conference topic ideas. + +### Generating talk ideas +Comedians have to generate new ideas (jokes) all the time. Demanding jobs such as Saturday Night Live require new scripts every week. It's part of the job, so quickly generating ideas is the first skill they teach you at comedy school. + +Here's what I learned at The Second City (the comedy school where Tina Fey, Stephen Colbert, and Steve Carell studied). To generate heaps of ideas, get a blank piece of paper (or digital equivalent) and start writing down ideas **without judging them or editing them.** I suggest setting a short timer to timebox the activity, for example 10 minutes. + +The most important point about this exercise is not pre-judging yourself. Humans are not good at multi-threading. If you're busy judging your ideas, you don't have enough brain power to be creative. Give yourself the permission to come up with crappy ideas. This is only an exercise and nobody is going to see what you write down. + +You can also use prompts to help you think of talk ideas: +* What have I worked on in the last 12 months (or longer)? +* Where have I been spending my time over the past year? +* What are the technologies that I'm interested in? +* What have I been reading about? + +After the timer is up and you have your ideas, then you can look through and start selecting your most promising ideas. Remember, only start judging after finishing writing down all the ideas. + +### Testing talk ideas +It's useful to think about the conference proposal selection process from the perspective of a conference organiser. I interviewed Benjie, part of the team organising the GraphQL Conference and Technical Steering Committee, for his advice. He told me, the most important thing he looked for was **interesting topics and unique perspectives**. The most important factor in getting accepted to speak at a conference is having an idea that resonates. + +So how do you know if your idea is interesting? An effective way to assess your talk ideas is to test them with colleagues. If your idea resonates with them, you've probably found an idea that many developers want to learn about. + +Test your conference ideas where it's appropriate. Perhaps a team demo, brown bags, meetups, writing an internal blog, or simply talking to colleagues. What grabs their attention? Which conversation topics come up again and again? + +### Narrowing down the list +To maximise your chances of getting selected, you should only submit your most promising talk ideas. + +Try and rank your remaining conference talk ideas with these prompts (you'll see why in the next section): +* Which of these ideas resonated most with colleagues? +* Which of these ideas do I have the most expertise in? +* Which of these ideas am I most proud of, or most excited by? + +I usually only have one or two proposals at a time, which I submit to many conferences. You might have more ideas, but try and keep your list short. Be efficient with your time and only submit the ideas you are sure about. + +## Writing the proposal +Here are my top tips, including suggestions from Benjie. + +After explaining these tips, in the next section I'll share the full text of my GraphQL Conference proposal, so you can see how achievable this is. + +### Get straight to the point +A conference organiser needs to understand what your proposal is about within the first few seconds of reading your proposal. Get straight to the point about what you are going to share. + +Conference organisers don't have time to call you and ask for clarification, so you must make sure what you write is very clear. Ask colleagues and friends to review your proposal for clarity. + +### A proposal is like a movie trailer +You'll see below, a proposal is very short. You'll usually be given a small word limit. + +You only have enough room to explain the main idea of your talk. You don't have enough room to explain all the points you will present in the talk. This is like a movie trailer. Show just enough excitement to grab a person's interest, but don't give the full story away. If they want to know all the details, they'll have to accept your talk first! + +The proposal never contains slides nor speech content. You write slides and the speech after being accepted, so don't worry about having this ready beforehand. + +### Explain why you're the best person to give the talk +Demonstrate your credentials and why you're the best person to give this talk. Explain why you are knowledgeable about the topic. + +Benjie said he was looking for **unique perspectives**. Demonstrate why you're uniquely qualified to deliver this talk. + +A conference organiser might not know who you are. Explaining your credentials is essential so the organiser trusts you to deliver on your talk proposal. + +### Emphasis community connections (optional) +If you have participated in the community, write about how you've contributed to the community. Similar to the previous point, a conference organiser doesn't know anything about most applicants. If the organisers have seen or interacted with you already, they will have more trust in you. + +I've been involved in the GraphQL community as a maintainer of GraphQL Java and contributed to the specification. The conference organisers trusted me to deliver the talk because they could see I was already contributing to the community. + +### Save your work +Save your proposal, so you can recycle the proposal for other conferences. It also means you're protected in case a website loses your work. + +## My GraphQL Conference proposal in full +This was the conference proposal that got accepted for the GraphQL Conference in 2023. See how I used the tips above in the additional notes below. + +> **Title:** How to make your first open source contribution (1) +> +> **Description:** +> Have you always wanted to make an open source contribution, but not sure where to start? (2) +> +> Getting started with open source is much easier than it seems. +> +> A year ago, I started regularly contributing to GraphQL Java and the GraphQL Scalars project. I caught the open source bug and made it a habit, and now I'm a maintainer of GraphQL Java (3). It has been an incredible learning experience, and it has been very rewarding to meet the engineers using the library all over the world. +> +> But it wasn't always an open source fairytale! Many years ago I tried to contribute to another project, and it was a total failure. I didn't have a great experience and it put me off open source for a long time. In this talk, I want to explain what I did differently to succeed this time around (4). +> +> **Speaker bio:** +> I am a maintainer of GraphQL Java and software engineer at Atlassian (5). I've published a book, GraphQL with Java and Spring, all about the official Spring for GraphQL integration and the GraphQL Java library. + +Notice my proposal was very short, but it was also very clear. A tip: when you ask colleagues to review your proposal, don't ask them "was it clear?" because they'll probably say "yes" to be polite. If you want more accurate feedback, instead ask them to explain the proposal back to you. + +Additional commentary on my proposal +1. Straight to the point in the title: My talk is going to be about how a beginner can make their first open source contribution. I would avoid puns, jokes, and pop culture references in the title because they might not make sense to a reviewer and can detract from your message. +2. Why this talk is interesting: this is a common question many engineers have. +3. Emphasise your credentials to build trust, and emphasise community connections. +4. Why this talk is interesting: I didn't always succeed. I initially failed miserably, but made changes and then became a maintainer. Note that I don't actually explain any steps for how to make an open source contribution in this short proposal. I deliberately stopped short of explaining so you'll only find out if you accept my conference talk! Remember, this is like a movie trailer. Show just enough excitement to grab a person's interest, but don't give the story away. +5. Explaining my credentials, why I'm uniquely qualified to give this talk. I also mentioned where I work and the book so it's easier to verify my credentials. + +## Dealing with rejection +Rejection sucks, particularly after putting in so much effort to write a proposal. Even great talk proposals can still be rejected. Perhaps the conference organisers were looking for different topics, or there was some other factor you can't control. + +This is why I want to prepare you upfront, you will be applying to many conferences. If you keep trying, you will eventually get accepted. You can reuse most of your talk proposal for other conferences, so your effort is not wasted. You should only spend a few minutes on each subsequent application. + +If it helps, I tried to reframe my disappointment of getting rejected. Instead, I tried to make a game out of collecting rejections. My goal was to collect 100 conference rejections, because I knew every submission was improving my chances. Although I was rejected from quite a few conferences, I didn't achieve my "goal" of 100 rejections. + +When a rejection happens, it's worth remembering your reasons for wanting to speak at a conference, which I wrote about at the top of this page. I promise the payoff is worth the uncomfortable feeling of getting rejected. Don't give up. + +While I encourage you to continue trying, each rejection also gives you the opportunity to assess if there is anything you can do better next time. In my experience, conference organisers are usually too busy to deliver detailed feedback. You could instead ask a colleague or friend for help. Try to ask colleagues who have already spoken at conferences, as they've already achieved what you're aiming for. + +## Apply for GraphQLConf 2025 +In this page we walked through every thing you need to know for writing a successful conference proposal. + +You already have what it takes. I encourage you to apply to speak at GraphQLConf 2025! The call for proposals is open, [apply now!](https://sessionize.com/graphqlconf-2025). diff --git a/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/Comparison_Method.gif b/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/Comparison_Method.gif new file mode 100644 index 0000000000..f86362d7ed Binary files /dev/null and b/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/Comparison_Method.gif differ diff --git a/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/index.mdx b/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/index.mdx new file mode 100644 index 0000000000..38c369dae1 --- /dev/null +++ b/src/pages/blog/2025-04-02-seeking-graphql-subject-matter-experts/index.mdx @@ -0,0 +1,72 @@ +--- +title: "Seeking GraphQL Subject Matter Experts" +tags: ["blog"] +date: 2025-04-02 +byline: Jem Gillam +--- +## Help shape GraphQLConf's schedule! + +The GraphQLConf Programme Committee is looking for GraphQL Subject Matter Experts to help shape the talk schedule for this year's GraphQLConf in Amsterdam. As a volunteer in this role, you’ll spend time during the week of 19th-25th May 2025 comparing talk submissions within your area of expertise, contributing to the creation of an engaging, informative, and impactful agenda. + +![An example of using the comparison method in Sessionize](./Comparison_Method.gif) + +

An example of using the comparison method in Sessionize

+ +Ideal candidates are experienced GraphQL professionals with deep technical insight, industry awareness, and a passion for high-quality impartial content. We're particularly keen on hearing from open source contributors and maintainers of leading GraphQL clients, servers, tooling and implementations as well as consumers of GraphQL APIs. Your input will directly influence the conference experience, ensuring attendees get a mix of cutting-edge topics, practical insights, and exciting discussions. + +If you fit one or more of these categories, apply today! + +* Engineers and leaders behind large GraphQL service providers +* Industry experts with knowledge of GraphQL observability, telemetry and tracing +* GraphQL working group members (including all subcommittees) +* Maintainers and contributors to open source GraphQL projects +* Lead developers for large multi-faceted GraphQL deployments +* Polyglot practitioners with a broad knowledge base across different ways of developing and deploying GraphQL +* GraphQL security experts + +
+ + Apply Now + +
+ +## Timeline + +**27th April: Call for Subject Matter Experts closes** +4th May: Call for Speakers closes +5th - 16th May: You’ll be contacted to onboard you to our Sessionize system +**19th - 25th May: This is your week! You help to review the talk submissions** +26th May - 8th June: Program committee build the schedule, guided heavily by your ratings +11th June: Schedule published +8th - 10th September: GraphQL Conference in Amsterdam + +## The Talk Selection Process + +There are three groups involved in the talk selection process: + +* The Technical Steering Committee (TSC) +* The new Subject Matter Experts initiative (SMEs) ← This is YOU! +* The Program Committee + +After the submission period ends, the TSC will have a short period of time to assess the viability of proposed talks and discount any which fall short of the selection criteria: talks which are vendor pitches or off-topic will be rejected at this early stage. The TSC will then have a week to use a star rating system to rate the talks based on their quality and originality, as well as their importance to the GraphQL ecosystem. + +In parallel, the SMEs will be given a selection of the talk proposals based on their subject matter areas. They will rate the talks using a comparison method, where groups of three talks are compared to each other. This will help identify which talks are the strongest fit for the conference based on subject relevance, originality, and potential audience engagement. + + +After these two rating methods, each talk will have two scores: a star rating from the TSC based on conference fit, and a rating from the SMEs reflecting subject content. The Program Committee will then start with the most highly rated talks and work to produce the schedule. Whilst the aim is to produce a schedule reflecting the TSC and SME ratings, the Program Committee will also act as a curator: making sure there is a good balance of talks from across different industries and affiliations, as well as looking at speaker diversity in terms of demographics and a balance between experienced and new speakers. + +
+ + Apply to be an SME + +
diff --git a/src/pages/blog/2025-04-18-governing-board-recap.md b/src/pages/blog/2025-04-18-governing-board-recap.md new file mode 100644 index 0000000000..e1929e4c4a --- /dev/null +++ b/src/pages/blog/2025-04-18-governing-board-recap.md @@ -0,0 +1,22 @@ +--- +title: March 2025 GraphQL Foundation Board Meeting Recap +tags: ["blog"] +date: 2025-04-18 +byline: GraphQL Governing Board +--- + +_Note: The GraphQL Foundation Governing Board will be authoring monthly blog post summaries of their meetings. This is the first approved post, with more to come!_ + +GraphQL Foundation’s Governing Board gathered on March 20 for a productive meeting focused on transparency, community growth, and continued technical progress. One key highlight was the board’s support for hosting **biannual public “Town Hall”–style meetings**, inspired by the first such meeting at GraphQLConf 2024. These events—one of which will be held during GraphQLConf 2025 in September—aim to bring more visibility to the Foundation’s work and encourage community participation and input. + +On the technical front, the **Technical Steering Committee (TSC)** shared updates on nullability, upcoming changes to graphql-js, and ongoing work on the incremental delivery specification. The team also encouraged feedback from Board Members and the community on behalf of GraphQL over HTTP. + +The new [**Community Working Group**](https://github.com/graphql/community-wg), under the TSC, reported strong early engagement, including work on a refreshed GraphQL.org landing page and an open, async collaboration model based on GitHub issues. + +The **Marketing & Content Committee** reported that efforts are underway to produce a series of case studies and better support industry-specific adoption stories. The team is also exploring more tailored messaging and additional social media campaigns to promote the conference, Local initiatives, and GraphQL-related news. + +Preparations for GraphQLConf 2025 in Amsterdam are well underway. The CFP has seen increased submissions compared to last year, and new voting tools will enable more inclusive talk selection. Ticket sales are tracking to plan, and the Foundation is actively seeking additional sponsors to support the event. + +Finally, the **Budget Committee** presented a draft of a new membership pitch deck designed to better communicate the impact and benefits of joining the GraphQL Foundation. The committee is continuing to refine this deck and will solicit ongoing feedback on the messaging. + +Stay tuned for more updates as we continue working together to support the GraphQL ecosystem and community. If your organization is interested in sponsoring GraphQL Conf or contributing a case study, we’d love to hear from you! diff --git a/src/pages/blog/2025-05-15-governing-board-recap.md b/src/pages/blog/2025-05-15-governing-board-recap.md new file mode 100644 index 0000000000..13ce7ac04d --- /dev/null +++ b/src/pages/blog/2025-05-15-governing-board-recap.md @@ -0,0 +1,28 @@ +--- +title: 📣 April 2025 GraphQL Foundation Board Meeting Recap +tags: ["blog"] +date: 2025-05-15 +byline: GraphQL Governing Board +--- + +The GraphQL Foundation Governing Board met April 17 to discuss ongoing community efforts, technical progress, and upcoming events—read on for the highlights: + +### **🖥️ Website Redesign Underway** + +The first version of the new GraphQL.org design is live for community feedback on [GitHub](https://github.com/graphql/community-wg/issues/21#issuecomment-2766734209)! Championed by The Guild, the new site focuses on communicating GraphQL’s value to different types of users. Check it out on GitHub and [Figma](http://figma.com/proto/aPUvZDSxJfYDJtPd7GF2sB/GraphQL.org?page-id=10%3A13019&node-id=649-3367&viewport=-2607%2C336%2C0.13&t=eZKIRpRkrWRATgQb-9&scaling=scale-down&content-scaling=fixed&starting-point-node-id=649%3A3367&show-proto-sidebar=1)—your feedback is welcome. + +### **🌍 Planning GraphQL All-Hands** + +We had fabulous input and a great turn out for our first public board meeting, which was held at GraphQLConf 2024. We’re building on that idea with a plan to host twice-a-year **GraphQL All-Hands** sessions. These gatherings will celebrate progress, share strategic updates, and foster open discussion. The next one will take place at [GraphQLConf 2025](https://graphql.org/conf/2025/) this fall! + +### **📊 Community Survey Discussion** + +Several Board and community members are exploring a user survey to help shape technical priorities, improve documentation, and inform event content. The Board discussed options to help the effort start small and release iteratively—stay tuned! + +### **💸 Budget & Membership** + +We're exploring aligning our fiscal planning with GraphQLConf to better match our annual rhythm. We also celebrated progress on new community grants! 🎉 + +### **🎤 GraphQLConf 2025** + +We’re expanding community involvement in the CFP process by becoming a **Subject Matter Expert**—we’re looking for volunteers to help rank talks for the conference program. Also, we're proud to support an [ALS charity swim team](https://graphql.org/blog/graphql-stream-team/) happening before the conference. The CFP closed **May 12**. diff --git a/src/pages/blog/2025-05-31-graphiql-4/index.mdx b/src/pages/blog/2025-05-31-graphiql-4/index.mdx new file mode 100644 index 0000000000..ed8fd77d7f --- /dev/null +++ b/src/pages/blog/2025-05-31-graphiql-4/index.mdx @@ -0,0 +1,100 @@ +--- +title: GraphiQL 4.1 is Released +tags: [announcements, grants] +date: 2025-05-31 +byline: Dimitri Postolov +--- + +import { Callout } from "nextra/components" + +I'm thrilled to announce the release of **GraphiQL 4.1**! 🎉 + +Thanks to funding from the **GraphQL Foundation**, I'm working on migrating +GraphiQL to the Monaco code editor — a long-awaited update that's been on our +roadmap for years. + +> In fact, the [original issue](https://github.com/graphql/graphiql/issues/2326) +> was opened over **three years ago**! + +## Roadmap + +Migrating to the Monaco editor is a major milestone, and to ensure a smooth +transition for everyone, I've broken it down into several incremental releases: + +### GraphiQL 3.9 + +- Switched build system from Webpack to Vite +- Compiled the codebase using the new + [React Compiler](https://react.dev/learn/react-compiler) + +### GraphiQL 4 + +- Dropped support for React 16/17 +- Added support for React 19 +- Introduced a refreshed tabs UI +- New ESM-based CDN example +- Deprecated the legacy UMD CDN build + +### GraphiQL 4.1 _(This release)_ + +- Standalone Doc Explorer plugin +- Standalone History plugin +- Migrated state management from React context to + [zustand](https://zustand-demo.pmnd.rs) + +### GraphiQL 5 _(Coming Soon)_ + +- Migration from Codemirror to + [Monaco Editor](https://github.com/microsoft/monaco-editor) +- Replacing `codemirror-graphql` with + [`monaco-graphql`](https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql) +- Support for comments in **Variables** and **Headers** editors +- New examples: **GraphiQL x Vite** and **GraphiQL x Next.js** + + + For the full roadmap, check out the [tracking issue on + GitHub](https://github.com/graphql/graphiql/issues/3874). + + +## What's New + +GraphiQL 4 serves as a gateway to the upcoming GraphiQL 5, which will be powered +by the Monaco editor, the same editor used in VSCode. Upgrading to GraphiQL 4 is +an essential step if you're already using React 19. + +We've extracted **Doc Explorer** and **History** into standalone plugins, +allowing full customization of GraphiQL's built-in plugins in the **GraphiQL +5**. + +Under the hood, we've replaced React context with zustand, making the internal +state management simpler and more maintainable, and enabling faster iteration on +new features. + +### Time to Say Goodbye to UMD Builds! + +With React 19, +[UMD builds have been removed](https://react.dev/blog/2024/04/25/react-19-upgrade-guide#umd-builds-removed). +The React team now recommends using ESM-based CDNs like +[esm.sh](https://esm.sh). + +We've updated the +[CDN example](https://github.com/graphql/graphiql/tree/main/examples/graphiql-cdn) +to show how to use GraphiQL with [esm.sh](https://esm.sh). + +### How to Update + +Follow the step-by-step guide in our +[GraphiQL 4 migration documentation](https://github.com/graphql/graphiql/blob/main/docs/migration/graphiql-4.0.0.md). + +## What's Next? + +The development of **GraphiQL 5** is almost complete! You can checkout the last +[Live Preview](https://deploy-preview-3234--graphiql-test.netlify.app). + +The official release is just around the corner — arriving later **this June**! + +## Stay Connected + +Follow me, **Dima Machina**, on [𝕏](https://x.com/dimaMachina_) and +[GitHub](https://github.com/dimaMachina) to stay up to date with the latest +updates! diff --git a/src/pages/blog/graphql-stream-team.mdx b/src/pages/blog/graphql-stream-team.mdx new file mode 100644 index 0000000000..f95e10e502 --- /dev/null +++ b/src/pages/blog/graphql-stream-team.mdx @@ -0,0 +1,35 @@ +--- +title: Join the GraphQL Stream Team at GraphQLConf 2025! +tags: ["blog"] +date: 2025-04-29 +byline: GraphQLConf Programming Committee +--- + +We're excited to announce that this year, alongside GraphQLConf 2025 in Amsterdam, we’re diving into something a little different. This is your once in a lifetime opportunity to swim in the Amsterdam canals and craft some fin-tastic puns. We've created a team to participate in the [Amsterdam City Swim](https://www.amsterdamcityswim.nl/), and we’d love for you to join the [GraphQL Stream Team](https://www.amsterdamcityswim.nl/teams/graphql-stream-team) on Sunday, September 7th! + +**Why We're Swimming** + +The Amsterdam City Swim isn’t just a unique athletic event—it’s a powerful fundraiser supporting research into ALS (amyotrophic lateral sclerosis), a devastating neurological disease that still has no cure. Every stroke we take helps raise money and awareness, and contributes to the ongoing fight against ALS. + +As developers, technologists, and open source enthusiasts, we often work together to solve complex problems. Now, we’re channeling that same energy into something beyond our everyday work—supporting a cause that impacts lives around the world. Our goal is to raise €2,500. + +**Who Can Join?** + +Anyone is welcome, even if you aren’t able to attend GraphQLConf! All you need is a swimsuit/wetsuit and goggles. Whether you're a seasoned swimmer or just in it for the adventure, we want you. **There are two different distance options - 750m + 2.25 km.** + +**Not a Fish?** + +We love a fan club! We’ll arrange a meetup spot for spectators and a post-swim soiree. + +**Ready to Take the Plunge?** + +* Sign up for our team: [GraphQLConf Stream Team](https://www.amsterdamcityswim.nl/teams/graphql-stream-team) +* Make a [donation](https://www.amsterdamcityswim.nl/teams/graphql-stream-team/donate) +* Spread the word: Invite your colleagues, friends, and family +* Pack your swim gear for Amsterdam! + +**Let’s Make a Splash** + +GraphQLConf 2025 is already shaping up to be an unforgettable event. Let’s make it even more meaningful by showing what our community can do when we come together for a good cause. + +Are you in? We welcome you with open fins! diff --git a/src/pages/community/foundation/community-grant.mdx b/src/pages/community/foundation/community-grant.mdx index 5bb17964de..a233a9f885 100644 --- a/src/pages/community/foundation/community-grant.mdx +++ b/src/pages/community/foundation/community-grant.mdx @@ -18,9 +18,9 @@ upon funding that is received as membership dues for the GraphQL Foundation. This is one way in which the GraphQL Foundation directly supports the ongoing health of the GraphQL developer ecosystem. -We encourage you to be creative in your grant application, and -propose tasks that are straightforward to articulate, achievable in three -months, and bounded in scope. +We encourage you to be creative in your grant application, and propose tasks +that are straightforward to articulate, achievable in three months, and bounded +in scope. Examples include: @@ -33,18 +33,17 @@ Examples include: - Other user experience improvement ideas for the [graphql.org][] website and/or [github.com/graphql][] -We are not funding work on projects outside https://github.com/graphql/ at this time. +We are not funding work on projects outside https://github.com/graphql/ at this +time. ## How to apply -The GraphQL Community Grant Program [accepts applications at any -time][application-form], and evaluates all undecided applications at least twice -per year. All applications will be closed after an evaluation cycle has -completed. Applicants may re-apply at any point. - To apply, please complete the [GraphQL Community Grant Program application][application-form]. +The GraphQL Community Grant Program accepts applications at any time. Applicants +can only have one active grant at a time, but may re-apply at any time. + ## FAQs ### Do I need to be developing the specification or code to apply? @@ -65,14 +64,13 @@ The grant amount offered will depend on our available funding and the number of approved grants per cycle. Individual grants are expected to be between $1,000 and $10,000 USD. When you apply you can select what size of grant you feel would be appropriate, but if approved you may be offered a different amount and it -will be up to you if you wish to proceed or not. +will be your choice whether to proceed. ### When can I expect to receive a response about my application? -We will review applications at least twice per year, on our about the end of May -and on or about the end of November. However, we will endeavor to review -applications as they come in and you will receive a response within 2 months of -review. +We will review applications at least twice per year; however, we endeavor to +review applications as they come in and you will receive a response within 2 +months of review. ### How often can I apply? @@ -81,9 +79,10 @@ frequently as you like. ### Who is eligible? -Any individual working in the GraphQL developer community who can receive a -payment from a US-based organization. Please note that this program is not -work-for-hire, and this is not an employment arrangement. +Any individual working in the GraphQL developer community who can legally +receive a payment from a US-based organization, including meeting any local tax +or legal requirements. Please note that this program is not work-for-hire, and +this is not an employment arrangement. _Only individuals are eligible to receive funding._ @@ -104,9 +103,49 @@ directly improves the GraphQL Foundation projects. ### Do I have to sign anything? Yes, if your proposal is selected you will need to sign the GraphQL Grantee -Agreement ([preview][agreement-preview] in order to receive the funding). It is +Agreement ([preview][agreement-preview]) in order to receive the funding. It is your responsibility to read and understand the contents of the agreement. +### What currencies are grants awarded in? + +All grants are awarded in United States Dollars (USD), so they should be +requested in USD. The amount specified in the grant agreement is fixed in USD +and will not be adjusted for currency fluctuations, conversion rates, or any +other exchange-related considerations. Recipients are responsible for any +associated currency conversion or banking fees. + +### When are grant funds disbursed? + +Grants are typically disbursed in full upon successful completion of the agreed +deliverables. However, in select cases, individuals with a demonstrated history +of substantial contributions to GraphQL Foundation projects may be eligible to +receive a small portion of the grant amount as an advance. Any such advance is +entirely at the discretion of the GraphQL Foundation and must be agreed upon in +writing prior to the commencement of the grant work. The remainder will be +disbursed only upon successful completion of the agreed deliverables. + +### How does the review process work? + +After submission, the GraphQL TSC's appointed grants representative is notified +and typically reviews the application within two working weeks. If the grant is +clearly out of scope, it will be declined with an explanation. If more +information is needed, it will be requested. Otherwise, the application proceeds +to the full TSC for review, discussion, and voting. + +The TSC aims to provide feedback within a further 2–3 working weeks, though this +may take longer depending on availability or complexity. If it takes longer than +3 weeks, the applicant will be informed. + +At the end of the review process, one of three outcomes is likely: + +1. The application is accepted, and next steps (contract, invoicing, etc.) are + initiated. +2. Changes are requested (e.g. revised scope or funding). +3. The application is declined, typically with guidance for resubmission. + +Note: Timelines are best-effort and may shift due to holidays, travel, or other +factors. + ## More information If you have questions, please contact [operations@graphql.org][]. @@ -116,4 +155,5 @@ If you have questions, please contact [operations@graphql.org][]. [github.com/graphql]: https://github.com/graphql [operations@graphql.org]: mailto:operations@graphql.org [agreement-preview]: https://grantee-agreement-preview.graphql.org -[application-form]: https://docs.google.com/forms/d/e/1FAIpQLSciopqGoQE2hBhxsb5E6dq12VrD221Zv4dsGWa1nQM35FT1nA/viewform?usp=sf_link +[application-form]: + https://docs.google.com/forms/d/e/1FAIpQLSciopqGoQE2hBhxsb5E6dq12VrD221Zv4dsGWa1nQM35FT1nA/viewform?usp=sf_link diff --git a/src/pages/community/foundation/local-initiative.mdx b/src/pages/community/foundation/local-initiative.mdx index 7eb9410a7b..fd479d983e 100644 --- a/src/pages/community/foundation/local-initiative.mdx +++ b/src/pages/community/foundation/local-initiative.mdx @@ -63,6 +63,38 @@ shall not be referred to as "official", but are still encouraged to follow the guidelines that are applicable (in particular, the Code of Conduct and Brand Guidelines must still be honoured). +### Local identity + +Locals are encouraged to use the name of their area in their Local name and identity. +The area chosen to be in the Local name should be meaningfully "local." It should +be culturally identified as a "local area," and at its largest should be a region that you +can reasonably commute within by public or private transport for an evening event. Often +this is a city, but we appreciate that's an imperfect simplification. + +
+ - GraphQL San Francisco +
+
+ - GraphQL California +
+ +If a brand or company wishes to be featured in the Local's identity, it must take secondary +precedence after the local area name and GraphQL: + +
+
+ - London GraphQL sponsored by Acme + - London GraphQL hosted by Acme and Brand X + - London GraphQL
sponsored by Acme +- London GraphQL
hosted by Acme and Brand X +
+
+ - Acme GraphQL + - Acme presents London GraphQL + - London GraphQL
presented by Acme +
+
+ ## Support Each approved Local is entitled to request the following support for each diff --git a/src/pages/community/foundation/members.mdx b/src/pages/community/foundation/members.mdx index 7351aaad27..84de1e800d 100644 --- a/src/pages/community/foundation/members.mdx +++ b/src/pages/community/foundation/members.mdx @@ -16,6 +16,6 @@ or [complete a membership application](https://join.graphql.org). diff --git a/src/pages/graphql-js/running-an-express-graphql-server.mdx b/src/pages/graphql-js/running-an-express-graphql-server.mdx index c73b403198..230b67a5e9 100644 --- a/src/pages/graphql-js/running-an-express-graphql-server.mdx +++ b/src/pages/graphql-js/running-an-express-graphql-server.mdx @@ -52,6 +52,8 @@ You can run this GraphQL server with: node server.js ``` +At this point you will have a running GraphQL API; but you can't just visit it in your web browser to use it - you need a GraphQL client to issue GraphQL queries to the API. Let's take a look at how to add the GraphiQL (GraphQL with an `i` in the middle) integrated development environment to your server. + ## Using GraphiQL [GraphiQL](https://github.com/graphql/graphiql) is GraphQL's IDE; a great way of querying and exploring your GraphQL API. diff --git a/src/pages/learn/authorization.mdx b/src/pages/learn/authorization.mdx index da91da0089..f23fab82ef 100644 --- a/src/pages/learn/authorization.mdx +++ b/src/pages/learn/authorization.mdx @@ -33,7 +33,7 @@ function Post_body(obj, args, context, info) { } ``` -Notice that we define "author owns a post" by checking whether the post's `authorId` field equals the current user’s `id`. Can you spot the problem? We would need to duplicate this code for each entry point into the service. Then if the authorization logic is not kept perfectly in sync, users could see different data depending on which API they use. Yikes! We can avoid that by having a [single source of truth](/learn/thinking-in-graphs/#business-logic-layer) for authorization, instead of putting it the GraphQL layer. +Notice that we define "author owns a post" by checking whether the post's `authorId` field equals the current user’s `id`. Can you spot the problem? We would need to duplicate this code for each entry point into the service. Then if the authorization logic is not kept perfectly in sync, users could see different data depending on which API they use. Yikes! We can avoid that by having a [single source of truth](/learn/thinking-in-graphs/#business-logic-layer) for authorization, instead of putting it in the GraphQL layer. Defining authorization logic inside the resolver is fine when learning GraphQL or prototyping. However, for a production codebase, delegate authorization logic to the business logic layer. Here’s an example of how authorization of the `Post` type's fields could be implemented separately: diff --git a/src/pages/learn/queries.mdx b/src/pages/learn/queries.mdx index b34e103c07..ce9c7ca617 100644 --- a/src/pages/learn/queries.mdx +++ b/src/pages/learn/queries.mdx @@ -55,7 +55,7 @@ If the only thing we could do was traverse objects and their fields, GraphQL wou ```graphql type Query { - droid(id: ID!): Droid + human(id: ID!): Human } ``` diff --git a/src/pages/learn/response.mdx b/src/pages/learn/response.mdx index d93c1fb855..27f547f9d5 100644 --- a/src/pages/learn/response.mdx +++ b/src/pages/learn/response.mdx @@ -41,6 +41,7 @@ In addition to the `data` key, the GraphQL specification outlines how [errors](h Request errors typically occur because the client made a mistake. For example, there may be a _syntax error_ in the document, such as a missing bracket or the use of an unknown root operation type keyword: +{/* */} ```graphql # { "graphiql": true } operation { @@ -103,7 +104,7 @@ As with network calls to any type of API, network errors that are not specific t ## Extensions -The final top-level key allowed by the GraphQL specification in a response is the `extentions` key. This key is reserved for GraphQL implementations to provide additional information about the response and though it must be an object if present, there are no other restrictions on what it may contain. +The final top-level key allowed by the GraphQL specification in a response is the `extensions` key. This key is reserved for GraphQL implementations to provide additional information about the response and though it must be an object if present, there are no other restrictions on what it may contain. For example, some GraphQL servers may include telemetry data or information about rate limit consumption under this key. Note that what data is available in `extensions` and whether this data is available in production or development environments will depend entirely on the specific GraphQL implementation. @@ -119,4 +120,4 @@ To recap what we've learned about GraphQL response formats: - When a field error occurs during execution, there will be a description of the issue in the `errors` key and there may be partial data included with the `data` key - GraphQL implementations may include additional arbitrary information about the response in the `extensions` key -Now that you understand the different phases of a GraphQL request and how responses are provided to clients, head over to the [Introspection](/learn/introspection) page to learn about how a GraphQL server can query information about its own schema. \ No newline at end of file +Now that you understand the different phases of a GraphQL request and how responses are provided to clients, head over to the [Introspection](/learn/introspection) page to learn about how a GraphQL server can query information about its own schema. diff --git a/src/pages/learn/schema.mdx b/src/pages/learn/schema.mdx index c47a6bf9d7..6ad4d7e6d8 100644 --- a/src/pages/learn/schema.mdx +++ b/src/pages/learn/schema.mdx @@ -58,7 +58,7 @@ The language is readable, but let's go over it so that we can have a shared voca - `name` and `appearsIn` are [fields](#object-types-and-fields) on the `Character` type. That means that `name` and `appearsIn` are the only fields that can appear in any part of a GraphQL query that operates on the `Character` type. - `String` is one of the built-in [Scalar types](#scalar-types). These are types that resolve to a single scalar value and can't have sub-selections in the query. We'll go over Scalar types more later. - `String!` means that the field is a [Non-Null type](#non-null), meaning the GraphQL service promises to give you a value whenever you query this field. In SDL, we represent those with an exclamation mark. -- `[Episode!]!` represents an [List type](#list) of `Episode` objects. When a List is Non-Null, you can always expect an array (with zero or more items) when you query the `appearsIn` field. In this case, since `Episode!` is also Non-Null within the list, you can always expect every item in the array to be an `Episode` object. +- `[Episode!]!` represents a [List type](#list) of `Episode` objects. When a List is Non-Null, you can always expect an array (with zero or more items) when you query the `appearsIn` field. In this case, since `Episode!` is also Non-Null within the list, you can always expect every item in the array to be an `Episode` object. Now you know what a GraphQL Object type looks like and how to read the basics of SDL. @@ -210,6 +210,7 @@ type Character { As we see above, the Non-Null and List modifiers can be combined. For example, you can have a List of Non-Null `String` types: +{/* */} ```graphql myField: [String!] ``` @@ -225,6 +226,7 @@ myField: ["a", null, "b"] // error Now, let's say we defined a Non-Null List of `String` types: +{/* */} ```graphql myField: [String]! ``` @@ -240,6 +242,7 @@ myField: ["a", null, "b"] // valid Lastly, you can also have a Non-Null List of Non-Null `String` types: +{/* */} ```graphql myField: [String!]! ``` @@ -413,7 +416,7 @@ Most of the examples we've covered on this page demonstrate how Object, Scalar, So far, we've only talked about using scalar values (like Enums or String types) as an input type for a field argument. However, you can also pass complex objects as arguments using an [Input Object type](https://spec.graphql.org/draft/#sec-Input-Objects), which is the last kind of named types in GraphQL that we'll explore. -This is particularly valuable in the case of [mutations](/learn/queries/#mutations), where you might want to pass in a whole object to be created. In SDL, Input Object types look similar to regular Object types, but with the keyword `input` instead of `type`: +This is particularly valuable in the case of [mutations](/learn/mutations/), where you might want to pass in a whole object to be created. In SDL, Input Object types look similar to regular Object types, but with the keyword `input` instead of `type`: ```graphql input ReviewInput { diff --git a/tailwind.config.ts b/tailwind.config.ts index 6a71eba9d0..639673a139 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,6 +1,8 @@ +import { fontFamily } from "tailwindcss/defaultTheme" import type { Config } from "tailwindcss" import typography from "@tailwindcss/typography" - +import plugin from "tailwindcss/plugin" +import containerQueries from "@tailwindcss/container-queries" const config: Config = { content: ["./src/**/*.{js,ts,jsx,tsx,mdx}", "./theme.config.tsx"], theme: { @@ -9,10 +11,59 @@ const config: Config = { padding: "1rem", }, extend: { + fontFamily: { + sans: [ + `var(--font-sans, ${fontFamily.sans.slice(0, 3).join(", ")})`, + ...fontFamily.sans, + ], + mono: [ + `var(--font-mono, ${fontFamily.mono.slice(0, 3).join(", ")})`, + ...fontFamily.mono, + ], + }, + screens: { + "3xl": "1920px", + }, colors: { primary: "#e10098", "conf-black": "#0e031c", black: "#1b1b1b", + + // #region new design system colors + "pri-lighter": "hsl(var(--color-pri-lighter) / )", + "pri-light": "hsl(var(--color-pri-light) / )", + "pri-base": "hsl(var(--color-pri-base) / )", + "pri-dark": "hsl(var(--color-pri-dark) / )", + "pri-darker": "hsl(var(--color-pri-darker) / )", + + "sec-lighter": "hsl(var(--color-sec-lighter) / )", + "sec-light": "hsl(var(--color-sec-light) / )", + "sec-base": "hsl(var(--color-sec-base) / )", + "sec-dark": "hsl(var(--color-sec-dark) / )", + "sec-darker": "hsl(var(--color-sec-darker) / )", + + // We're using 3-letter color names to avoid conflicting + // with the old `neutral` color. + "neu-0": "hsl(var(--color-neu-0) / )", + "neu-50": "hsl(var(--color-neu-50) / )", + "neu-100": "hsl(var(--color-neu-100) / )", + "neu-200": "hsl(var(--color-neu-200) / )", + "neu-300": "hsl(var(--color-neu-300) / )", + "neu-400": "hsl(var(--color-neu-400) / )", + "neu-500": "hsl(var(--color-neu-500) / )", + "neu-600": "hsl(var(--color-neu-600) / )", + "neu-700": "hsl(var(--color-neu-700) / )", + "neu-800": "hsl(var(--color-neu-800) / )", + "neu-900": "hsl(var(--color-neu-900) / )", + + blk: "#000", + + /** + * GraphQL Rhodamine as per the trademark guidelines + * https://www.graphql.org/brand/ + */ + rhodamine: "#e10098", + // #endregion new design system colors }, backgroundImage: { "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", @@ -32,7 +83,101 @@ const config: Config = { }, }, }, - plugins: [typography], + plugins: [ + typography, + containerQueries, + plugin(({ addUtilities }) => { + // heading styles + addUtilities({ + ".typography-d1, .typography-h1, .typography-h2, .typography-h3": { + lineHeight: "1.2", + }, + ".typography-d1": { + fontSize: "48px", + "@screen lg": { + fontSize: "96px", + }, + }, + ".typography-h1": { + fontSize: "40px", + "@screen lg": { + fontSize: "72px", + }, + }, + ".typography-h2": { + fontSize: "32px", + "@screen md": { + fontSize: "48px", + }, + }, + ".typography-h3": { + fontSize: "24px", + "@screen md": { + fontSize: "32px", + }, + }, + }) + + // paragraph styles + addUtilities({ + ".typography-body-lg, .typography-body-md, .typography-body-sm, .typography-body-xs": + { + lineHeight: "1.5", + }, + ".typography-body-lg": { + fontSize: "16px", + "@screen md": { + fontSize: "20px", + }, + }, + ".typography-body-md": { + fontSize: "14px", + "@screen md": { + fontSize: "16px", + }, + }, + ".typography-body-sm": { + fontSize: "12px", + "@screen md": { + fontSize: "14px", + }, + }, + ".typography-body-xs": { + fontSize: "10px", + "@screen md": { + fontSize: "12px", + }, + }, + }) + + // other text styles + addUtilities({ + ".typography-button, .typography-tagline": { + fontSize: "16px", + lineHeight: "1", + }, + ".typography-tagline": { + textTransform: "uppercase", + }, + ".typography-menu": { + fontFamily: "var(--font-mono)", + fontSize: "14px", + lineHeight: "1", + textTransform: "uppercase", + }, + }) + + addUtilities({ + ".typography-link": { + color: "theme('colors.neu-800')", + textDecoration: "underline", + "&:hover": { + textDecoration: "none", + }, + }, + }) + }), + ], darkMode: ["class", 'html[class~="dark"]'], } export default config diff --git a/vercel.json b/vercel.json index c9dcc98bc5..ca46883581 100644 --- a/vercel.json +++ b/vercel.json @@ -52,7 +52,7 @@ }, { "source": "/graphql-js/:path*", - "destination": "https://graphql-js.org/:path*", + "destination": "https://graphql-js.org/docs/:path*", "permanent": true }, {