mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix(graphql): handle invalid schemas gracefully in query editor (#7269)
Prevent app crashes when loading GraphQL schemas with validation errors (e.g., object types with no fields). The fix: - Validates schemas using validateSchema() and shows warnings for issues - Still loads the schema so autocomplete continues to work - Wraps the CodeMirror GraphQL linter with error handling to catch any validation errors during linting Fixes #4529 Co-authored-by: Chirag Chandrashekhar <cchirag85@gmail.com>
This commit is contained in:
committed by
GitHub
parent
b0d0e4aabc
commit
da1d7e51d2
@@ -1,9 +1,28 @@
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { buildClientSchema, buildSchema } from 'graphql';
|
||||
import { buildClientSchema, buildSchema, validateSchema } from 'graphql';
|
||||
import { fetchGqlSchema } from 'utils/network';
|
||||
import { simpleHash, safeParseJSON } from 'utils/common';
|
||||
|
||||
const buildAndValidateSchema = (data) => {
|
||||
let schema;
|
||||
if (typeof data === 'object') {
|
||||
schema = buildClientSchema(data);
|
||||
} else {
|
||||
schema = buildSchema(data);
|
||||
}
|
||||
|
||||
// Validate the schema to catch issues like empty object types
|
||||
// The GraphQL spec requires object types to have at least one field
|
||||
const validationErrors = validateSchema(schema);
|
||||
if (validationErrors.length > 0) {
|
||||
const errorMessages = validationErrors.map((e) => e.message).join('; ');
|
||||
console.warn('GraphQL schema has validation issues:', errorMessages);
|
||||
}
|
||||
|
||||
return { schema, validationErrors };
|
||||
};
|
||||
|
||||
const schemaHashPrefix = 'bruno.graphqlSchema';
|
||||
|
||||
const useGraphqlSchema = (endpoint, environment, request, collection) => {
|
||||
@@ -19,13 +38,11 @@ const useGraphqlSchema = (endpoint, environment, request, collection) => {
|
||||
return null;
|
||||
}
|
||||
let parsedData = safeParseJSON(saved);
|
||||
if (typeof parsedData === 'object') {
|
||||
return buildClientSchema(parsedData);
|
||||
} else {
|
||||
return buildSchema(parsedData);
|
||||
}
|
||||
} catch {
|
||||
localStorage.setItem(localStorageKey, null);
|
||||
const { schema } = buildAndValidateSchema(parsedData);
|
||||
return schema;
|
||||
} catch (err) {
|
||||
localStorage.removeItem(localStorageKey);
|
||||
console.warn('Failed to load cached GraphQL schema:', err.message);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -72,13 +89,19 @@ const useGraphqlSchema = (endpoint, environment, request, collection) => {
|
||||
data = await loadSchemaFromIntrospection();
|
||||
}
|
||||
if (data) {
|
||||
if (typeof data === 'object') {
|
||||
setSchema(buildClientSchema(data));
|
||||
} else {
|
||||
setSchema(buildSchema(data));
|
||||
}
|
||||
const { schema, validationErrors } = buildAndValidateSchema(data);
|
||||
setSchema(schema);
|
||||
localStorage.setItem(localStorageKey, JSON.stringify(data));
|
||||
toast.success('GraphQL Schema loaded successfully');
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
const errorMessages = validationErrors.map((e) => e.message).join('; ');
|
||||
toast(`Schema validation issues: ${errorMessages}`, {
|
||||
icon: '⚠️',
|
||||
duration: 5000
|
||||
});
|
||||
} else {
|
||||
toast.success('GraphQL Schema loaded successfully');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
|
||||
@@ -24,6 +24,25 @@ const CodeMirror = require('codemirror');
|
||||
const md = new MD();
|
||||
const AUTO_COMPLETE_AFTER_KEY = /^[a-zA-Z0-9_@(]$/;
|
||||
|
||||
const createSafeGraphQLLinter = () => {
|
||||
// Get the original GraphQL lint helper registered by codemirror-graphql
|
||||
const originalLinter = CodeMirror.helpers?.lint?.graphql?.[0];
|
||||
|
||||
return (text, options) => {
|
||||
try {
|
||||
if (originalLinter) {
|
||||
return originalLinter(text, options);
|
||||
}
|
||||
return [];
|
||||
} catch (error) {
|
||||
// Log the error but don't crash - return empty lint results
|
||||
// This can happen if the schema has validation issues
|
||||
console.warn('GraphQL lint error (schema may be invalid):', error.message);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default class QueryEditor extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -57,6 +76,7 @@ export default class QueryEditor extends React.Component {
|
||||
minFoldSize: 4
|
||||
},
|
||||
lint: {
|
||||
getAnnotations: createSafeGraphQLLinter(),
|
||||
schema: this.props.schema,
|
||||
validationRules: this.props.validationRules ?? null,
|
||||
// linting accepts string or FragmentDefinitionNode[]
|
||||
|
||||
Reference in New Issue
Block a user