Introducing Custom Checks

Tom HouléTom Houlé
Introducing Custom Checks

Today, we are releasing Custom Checks support in the Grafbase Schema Registry, available in Grafbase Cloud and Grafbase Enterprise Platform.

Custom Checks allow you to extend Schema Checks with your own logic, beyond composition, operation and proposal checks. You can plug in your own linter with your own configuration, or interact with internal services in your organization to enforce proper process and business rules around subgraph schemas.

  • Enforcing naming conventions beyond built-in lint rules
  • Validating domain-specific constraints (e.g., certain fields must always appear together)
  • Ensuring compliance with your organization's API design guidelines
  • Integrating with other systems to validate business logic, or for security review
  • Preventing anti-patterns specific to your implementation

To implement Custom Checks, you only need to expose a single HTTP endpoint that receives the schemas to check and returns diagnostics. They are typically stateless and easy to implement.

Here is an example implementation that enforces that mutation fields have a single corresponding input type in the schema:

const express = require('express'); const { parse, visit } = require('graphql'); const app = express(); app.use(express.json()); app.post('/custom-check', (req, res) => { const { subgraph } = req.body; const diagnostics = []; try { const parsedSchema = parse(subgraph.schema); const inputTypes = new Set(); const mutationFields = []; // Collect all input types visit(parsedSchema, { InputObjectTypeDefinition(node) { inputTypes.add(node.name.value); } }); // Check mutation fields visit(parsedSchema, { ObjectTypeDefinition(node) { if (node.name.value === 'Mutation') { node.fields.forEach(field => { mutationFields.push(field.name.value); // Check if there's a corresponding input type const expectedInputName = `${field.name.value}Input`; if (!inputTypes.has(expectedInputName)) { diagnostics.push({ message: `Mutation "${field.name.value}" should have a corresponding input type "${expectedInputName}"`, severity: "WARNING" }); } }); } } }); res.json({ diagnostics }); } catch (error) { res.status(500).json({ diagnostics: [{ message: `Failed to analyze schema: ${error.message}`, severity: "ERROR" }] }); } }); app.listen(3000, () => console.log('Custom check webhook running on port 3000'));

Custom Checks are available starting today for all Grafbase users. You can head to the docs page for more details.

Custom checks in their current form are synchronous. We have designed this feature in collaboration with users, and we want to make sure that it meets their needs and solves real world use cases. We foresee the need for async custom checks for checks that take longer, maybe because they rely on multiple internal services for diagnostics. We left room to easily add them to the implementation. If you have a use case for async custom checks, please reach out to us. We would love to understand your needs better and collaborate on shaping async checks that work for your concrete needs.

We are excited to see what you build with Custom Checks! If you have any feedback or questions, please don't hesitate to reach out and interact with our community.