-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Variables dependency incompatible with Apollo Server 2 #12
Comments
An option is to open up the array of functions that create the extensions to receive the same argument as the context creation. Here are the type definitions https://github.com/apollographql/apollo-server/blob/version-2/packages/apollo-server-core/src/types.ts#L56 |
@pa-bru Any thoughts on what @evans and @steverice are suggesting? |
Is there any update with this issue ? |
This is the workaround I'm currently using. // XXX: Evil hack to use graphql-cost-analysis
class EnhancedServer extends ApolloServer {
async createGraphQLServerOptions(
req: express.Request,
res: express.Response
): Promise<GraphQLOptions> {
const options = await super.createGraphQLServerOptions(req, res);
return {
...options,
validationRules: [
...options.validationRules,
costAnalysis({variables: req.body.variables})
]
};
}
}``` |
Another workaround is to provide dummy/mock variable values (as suggested by @zionts in Slack) like so: const apolloServer = new ApolloServer({
validationRules: [
costAnalysis({
variables: {
someQueryVarInYourSchema: 42,
someOtherQueryVarInYourSchema: false,
},
}),
],
}); It's brittle and doesn't scale well with large schemas, of course, but it works. |
@arianon thank you so much, the workaround worked perfectly! 💯 withspectrum/spectrum#3855 |
@arianon I had to change it to this: class CostAnalysisApolloServer extends ApolloServer {
async createGraphQLServerOptions(req, res) {
const options = await super.createGraphQLServerOptions(req, res);
options.validationRules = options.validationRules || [];
options.validationRules.push(graphqlCostAnalysis({
variables: req.body.variables,
maximumCost: 1234,
defaultCost: 1,
onComplete: (costs) => console.log(`costs: ${costs} (max: 1234)`)
}));
return options;
}
}
|
How about refactoring the code base to work as an apollo plugin? new ApolloServer({
plugins: [
{
requestDidStart: () => {
return {
// This is called after the validationRules.
didResolveOperation: requestContext => {
// requestContext.operations
// requestContext.request.variables
// Do cost analysis here.
},
}
},
},
],
}) The only problem I see is how to access the schema. This is currently done via @pa-bru Do you have an idea? |
Just passing through here, but thought I'd leave a note! It's true that validation rules cannot be dynamically changed for each request anymore in Apollo Server 2.x. However, the Also, if the intention is to run after validation, I would recommend using the appropriate hook rather than incorrectly leveraging const examplePlugin = () => {
let schema;
return {
serverWillStart({ schema: schemaAtStartup }) {
// We'll save a reference to the schema.
schema = schemaAtStartup;
},
requestDidStart() {
return {
validationDidStart() {
return function validationDidEnd() {
console.log("The schema was", schema);
throw new ForbiddenError("Too complex?");
}
},
}
},
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [examplePlugin],
}); Hope this helps! |
How do you handle array of operations?
|
FYI: I added the graphql-cost-analysis to my ApolloServer and found that because the Apollo GraphQL server options contain a reference to the server's validationRules, and not a copy, it is incorrect to push the cost analyzer directly onto the validationRules. Instead, you should make a copy of the rules. Otherwise you'll end up with an increasing number of duplicates in the rules array. The updated code to add the validation rule looks like this: class CostAnalysisApolloServer extends ApolloServer {
async createGraphQLServerOptions(req, res) {
const options = await super.createGraphQLServerOptions(req, res);
options.validationRules = options.validationRules ? options.validationRules.slice() : [];
options.validationRules.push(graphqlCostAnalysis({
variables: req.body.variables,
maximumCost: 1234,
defaultCost: 1,
onComplete: (costs) => console.log(`costs: ${costs} (max: 1234)`)
}));
return options;
}
} |
If you're using import { json } from "micro";
class CostAnalysisApolloServer extends ApolloServer {
async createGraphQLServerOptions(req, res) {
const options = await super.createGraphQLServerOptions(req, res);
// parse the body
const { variables } = await json(req)
options.validationRules = options.validationRules ? options.validationRules.slice() : [];
options.validationRules.push(graphqlCostAnalysis({
variables,
maximumCost: 1234,
defaultCost: 1,
onComplete: (costs) => console.log(`costs: ${costs} (max: 1234)`)
}));
return options;
}
} |
@P4sca1 that's a great solution however I am struggling to make it work. a little help will be appreciated const costAnalyzer = request => costAnalysis({ this.server = new ApolloServer({ |
Currently, the validation rule requires providing the
variables
object from the request becauseUnfortunately, version 2 of Apollo Server no longer allows dynamic configuration of all of its server options per-request, but rather only the
context
.validationRules
must be provided when the server is initialized and not within the context of the middleware. Therefore, all that each validation rule has access to is theValidationContext
and there's no built-in way to inject the request variables.I am reasonably certain that this is an intentional change.
It seems possible to remove
graphql-cost-analysis
's dependence on the fullvariables
object, given that theValidationContext
provides information about variable usages and also about field arguments.Is this feasible?
The text was updated successfully, but these errors were encountered: