Skip to content

Instantly share code, notes, and snippets.

@PedroHLC
Created August 19, 2024 14:45
Show Gist options
  • Save PedroHLC/133b43219aad72c810a0a55a5febb128 to your computer and use it in GitHub Desktop.
Save PedroHLC/133b43219aad72c810a0a55a5febb128 to your computer and use it in GitHub Desktop.
Validates a graphql query from stdin against a schema from http or file
#!/usr/bin/env node
/* Author: Pedro H L Campos <https://keybase.io/pedrohlc>
License: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
const { Source, buildSchema, buildClientSchema, getIntrospectionQuery, printSchema, validate, parse } = require('graphql');
const fs = require('fs');
async function main(stdin, argv) {
// Remove interpreter and script
argv.shift();
argv.shift();
if (argv.length != 1) {
console.error('Expeting a single argument with an URL or path to the schema, e.g.: ./gql-validate "http://localhost:5000/api"');
return 2;
}
if (stdin.isTTY) {
console.error('TTY in STDIN. Pipe a GQL Query instead!');
return 3;
}
// Doing it the hard way, for that timeout hack
const inputChunks = [];
stdin.setTimeout(100);
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', (chunk) => inputChunks.push(chunk));
const inputDataPromise = new Promise((resolve, reject) => {
stdin.on('end', () => resolve(inputChunks.join()));
stdin.on('error', () => resolve(''));
stdin.on('timeout', () => resolve(inputChunks.join())); // It's really hard to close stdin in Elixir's Port, let it timeout instead!
}).catch((_reason) => "");
const stdinData = await inputDataPromise;
if (stdinData.length < 1) {
console.error('Incomplete file in STDIN');
return 4;
}
// Two interesting ways to have the schema: URL or File
const schema =
argv[0].includes(":") ?
await fetch(argv[0], {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ query: getIntrospectionQuery() }),
})
.then((response) => response.json())
.then(({ data }) => buildClientSchema(data))
.catch((reason) => {
console.warn(reason);
return null;
})
: buildSchema(fs.readFileSync(argv[0], 'utf-8'));
if (!schema) {
console.error('Couldn\'t fetch or find schema');
return 4;
}
//console.debug(printSchema(schema));
const errors = validate(schema, parse(new Source(stdinData, 'Query.graphql', { line: 1, column: 1 })));
console.log(errors);
return errors.length > 0 ? 1 : 0;
}
main(process.stdin, process.argv).then(process.exit);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment