Skip to content

Instantly share code, notes, and snippets.

@archilkarchava
Created January 31, 2019 16:55
Show Gist options
  • Save archilkarchava/64efb7b9cdbca301da43d807a33fbb38 to your computer and use it in GitHub Desktop.
Save archilkarchava/64efb7b9cdbca301da43d807a33fbb38 to your computer and use it in GitHub Desktop.
import { ApolloServer, GraphQLOptions } from "apollo-server-express";
import { Request, Response } from "express";
import queryComplexity, {
fieldConfigEstimator,
simpleEstimator
} from "graphql-query-complexity";
// hack to use graphql-query-complexity analysis
export class ApolloServerWithQueryComplexity extends ApolloServer {
public async createGraphQLServerOptions(
req: Request,
res: Response
): Promise<GraphQLOptions> {
const options = await super.createGraphQLServerOptions(req, res);
if (options.validationRules) {
}
return {
...options,
validationRules: [
...(options.validationRules ? options.validationRules : []),
queryComplexity({
// The maximum allowed query complexity, queries above this threshold will be rejected
maximumComplexity: 20,
// The query variables. This is needed because the variables are not available
// in the visitor of the graphql-js library
variables: req.body.variables,
// Optional callback function to retrieve the determined query complexity
// Will be invoked weather the query is rejected or not
// This can be used for logging or to implement rate limiting
onComplete: (complexity: number) => {
console.log("Query Complexity:", complexity);
},
estimators: [
// Using fieldConfigEstimator is mandatory to make it work with type-graphql
fieldConfigEstimator(),
// This will assign each field a complexity of 1 if no other estimator
// returned a value. We can define the default value for field not explicitly annotated
simpleEstimator({
defaultComplexity: 1
})
]
}) as any
]
};
}
}
import * as connectRedis from "connect-redis";
import * as cors from "cors";
import * as dotenv from "dotenv";
import * as Express from "express";
import * as session from "express-session";
import { GraphQLSchema } from "graphql";
import "reflect-metadata";
import { formatArgumentValidationError } from "type-graphql";
import { createConnection } from "typeorm";
import { ApolloServerWithQueryComplexity } from "./ApolloServerWithQueryComplexity";
import { redis } from "./redis";
import { IMyContext } from "./types/MyContext";
import { createSchema } from "./utils/createSchema";
dotenv.config();
const main = async () => {
try {
await createConnection();
} catch (err) {
throw new Error(err);
}
let schema: GraphQLSchema;
try {
schema = await createSchema();
} catch (err) {
throw new Error(err);
}
const apolloServer = new ApolloServerWithQueryComplexity({
schema,
formatError: formatArgumentValidationError,
context: ({ req, res }: IMyContext) => ({ req, res })
});
const app = Express();
const RedisStore = connectRedis(session);
app.use(
cors({
credentials: true,
origin: "http://localhost:3000"
})
);
app.use(
session({
store: new RedisStore({
client: redis as any
}),
name: "qid",
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
maxAge: 1000 * 60 * 60 * 24 * 7 * 365 // 7 years
}
})
);
apolloServer.applyMiddleware({ app, cors: false });
app.listen(4000, () => {
console.log("Server started on http://localhost:4000/graphql");
});
};
main().catch(err => {
console.error(err);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment