@graphql-hive/gateway-testing
Version:
159 lines (154 loc) • 4.95 kB
JavaScript
;
var subgraph = require('@apollo/subgraph');
var gatewayRuntime = require('@graphql-hive/gateway-runtime');
var fusionComposition = require('@graphql-mesh/fusion-composition');
var executorHttp = require('@graphql-tools/executor-http');
var graphql = require('graphql');
var graphqlYoga = require('graphql-yoga');
function getEnvStr(key, opts = {}) {
const globalThat = opts.globalThis ?? globalThis;
let variable = globalThat.process?.env?.[key] || // @ts-expect-error can exist in wrangler and maybe other runtimes
globalThat.env?.[key] || // @ts-expect-error can exist in deno
globalThat.Deno?.env?.get(key) || // @ts-expect-error could be
globalThat[key];
if (variable != null) {
variable += "";
} else {
variable = void 0;
}
return variable?.trim();
}
function getEnvBool(key, opts = {}) {
return strToBool(getEnvStr(key, opts));
}
function strToBool(str) {
return ["1", "t", "true", "y", "yes", "on", "enabled"].includes(
(str || "").toLowerCase()
);
}
function isDebug() {
return getEnvBool("DEBUG");
}
function createGatewayTester(config) {
let runtime;
if ("supergraph" in config) {
runtime = gatewayRuntime.createGatewayRuntime({
maskedErrors: false,
logging: isDebug(),
...config
});
} else if ("subgraphs" in config) {
let buildSubgraphs2 = function() {
subgraphsRef.ref = (typeof subgraphsConfig === "function" ? subgraphsConfig() : subgraphsConfig).reduce(
(acc, subgraph) => {
const remoteSchema = buildRemoteSchema(subgraph);
return {
...acc,
[remoteSchema.name]: remoteSchema
};
},
{}
);
return Object.values(subgraphsRef.ref);
};
const subgraphsConfig = config.subgraphs;
const subgraphsRef = {
ref: null
};
runtime = gatewayRuntime.createGatewayRuntime({
maskedErrors: false,
logging: isDebug(),
...config,
supergraph: typeof config.subgraphs === "function" ? () => fusionComposition.getUnifiedGraphGracefully(buildSubgraphs2()) : fusionComposition.getUnifiedGraphGracefully(buildSubgraphs2()),
plugins: (ctx) => [
{
onFetch({ executionRequest, setFetchFn }) {
const subgraphName = executionRequest?.subgraphName;
if (!subgraphName) {
return;
}
if (!subgraphsRef.ref) {
throw new Error("Subgraphs are not built yet");
}
const subgraph = subgraphsRef.ref[subgraphName];
if (!subgraph) {
throw new Error(`Subgraph "${subgraphName}" not found`);
}
setFetchFn(subgraph.yoga.fetch);
}
},
...config.plugins?.(ctx) || []
]
});
} else if ("proxy" in config) {
const remoteSchema = buildRemoteSchema(config.proxy);
runtime = gatewayRuntime.createGatewayRuntime({
maskedErrors: false,
logging: isDebug(),
...config,
proxy: { endpoint: remoteSchema.url, headers: config.proxy.headers },
plugins: (ctx) => [
gatewayRuntime.useCustomFetch((url, options, context, info) => {
return remoteSchema.yoga.fetch(
// @ts-expect-error TODO: url can be a string, not only an instance of URL
url,
options,
context,
info
);
}),
...config.plugins?.(ctx) || []
]
});
} else {
throw new Error("Unsupported gateway tester configuration");
}
const runtimeExecute = executorHttp.buildHTTPExecutor({
endpoint: "http://gateway/graphql",
fetch: runtime.fetch,
headers: (execReq) => execReq?.rootValue.headers
});
return {
runtime,
// @ts-expect-error native and whatwg-node fetch has conflicts
fetch: runtime.fetch,
async execute(args) {
return runtimeExecute({
document: graphql.parse(args.query),
variables: args.variables,
operationName: args.operationName,
extensions: args.extensions,
rootValue: { headers: args.headers }
});
},
[graphqlYoga.DisposableSymbols.asyncDispose]() {
return runtime[graphqlYoga.DisposableSymbols.asyncDispose]();
},
async dispose() {
await runtime.dispose();
}
};
}
function buildRemoteSchema(config) {
const schema = "typeDefs" in config.schema ? subgraph.buildSubgraphSchema([
{
...config.schema,
typeDefs: graphql.parse(config.schema.typeDefs)
}
]) : config.schema;
const yoga = typeof config.yoga === "function" ? config.yoga?.(schema) : graphqlYoga.createYoga({
maskedErrors: false,
logging: isDebug(),
...config.yoga,
schema
});
const host = config.host || config.name;
const url = `http://${host}${yoga.graphqlEndpoint}`;
return {
name: config.name,
url,
schema,
yoga
};
}
exports.createGatewayTester = createGatewayTester;