ponder-enrich-gql-docs-middleware
Version:
A middleware for Ponder that allows devs to enrich their GraphQL docs with docstrings
97 lines (96 loc) • 4.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDocumentationMiddleware = createDocumentationMiddleware;
const graphql_1 = require("graphql");
const introspection_1 = require("./introspection");
/**
* Creates a middleware function that enhances GraphQL introspection queries with documentation.
*
* This middleware intercepts GraphQL introspection queries and adds documentation strings
* to the schema before returning it to the client. It's particularly useful for adding
* detailed documentation to your GraphQL API that will show up in tools like GraphiQL.
*
* @param docs - Documentation strings to add to the schema
* @param options - Configuration options for the middleware
* @returns A middleware function to use in your GraphQL server
*
* @example
* ```typescript
* import { createDocumentationMiddleware } from '@your-lib/graphql-docs';
* import { ponder } from 'ponder:registry';
*
* const docs = {
* User: "Represents a user in the system",
* "User.balance": "The user's balance"
* };
*
* const middleware = createDocumentationMiddleware(docs, { debug: true });
* ponder.use('/graphql', middleware);
* ```
*/
function createDocumentationMiddleware(docs, options = {}) {
const { debug = false } = options;
const log = debug
? (...args) => console.log("[GraphQL Docs]:", ...args)
: () => { };
/**
* The actual middleware function that processes GraphQL requests.
*
* @param context - The middleware context containing request and response
* @param next - Function to call the next middleware
*/
return function documentationMiddleware(context, next) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const body = yield context.req.raw.clone().text();
let parsed;
try {
parsed = JSON.parse(body);
}
catch (err) {
log("Failed to parse request body:", err);
return next();
}
if (!(parsed === null || parsed === void 0 ? void 0 : parsed.query)) {
log("No query found in request");
return next();
}
try {
const document = (0, graphql_1.parse)(parsed.query);
const isIntrospection = document.definitions.some((def) => {
if (def.kind === "OperationDefinition") {
return def.selectionSet.selections.some((sel) => sel.kind === "Field" && sel.name.value.startsWith("__"));
}
return false;
});
if (!isIntrospection) {
log("Not an introspection query");
return next();
}
yield next();
const response = yield context.res.clone().text();
const json = JSON.parse(response);
if ((_a = json === null || json === void 0 ? void 0 : json.data) === null || _a === void 0 ? void 0 : _a.__schema) {
log("Enhancing schema with documentation");
json.data = (0, introspection_1.addDocStringsToIntrospection)(json.data, docs);
context.res = new Response(JSON.stringify(json), {
headers: { "Content-Type": "application/json" },
});
}
}
catch (err) {
log("Error processing GraphQL request:", err);
throw err;
}
});
};
}