GraphQL-Codegen is an awesome tool that simply introspects your GraphQL Backend and generates the schema types for your frontend. It requires little to no configuration and is a great way to catch bugs early on in your schema. I replaced all the manually written types in my existing react apps and the code reduction was a humongous 30%!
But, there is a small problem. It needs introspection to be turned on for it to work. Easy enough in development, but a security risk in production. You don’t want to expose your schema to the world. So, what do you do?
Simplest solution. Just commit the schema files to your repository. But, it has a few drawbacks. Mainly because:
We tried this approach and it’s a bad one. Just before you build your frontend, you turn on introspection, and after you’re done, turn it off. This requires a lot of server restarts, is a pain to keep track of and is just not a good idea.
This is the approach that we finally settled on.
On the backend:
https://api.example.com/graphql-2f530e6e-bd6f-4c7b-87b6-d848e1407c7d
On the frontend:
// BACKEND
// server.ts
const server = new ApolloServer({
schema: applyMiddleware(schema, permissions),
introspection: false,
...rest,
});
const serverInternal = new ApolloServer({
schema: applyMiddleware(schema, servicePermissionsWithAllDisabled),
introspection: true,
...rest,
});
app.use("/graphql", cors<cors.CorsRequest>(), json(), ...rest);
// Internal endpoint for codegen
app.use(
"/graphql-2f530e6e-bd6f-4c7b-87b6-d848e1407c7d",
cors<cors.CorsRequest>(),
json(),
...rest,
);
// FRONTEND
// codegen.ts
import { CodegenConfig } from "@graphql-codegen/cli";
import dotenv from "dotenv";
dotenv.config();
const config: CodegenConfig = {
schema: process.env.INTERNAL_GRAPHQL_BACKEND,
// this assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
documents: ["src/**/*.{ts,tsx}"],
generates: {
"./src/__generated__/": {
preset: "client",
plugins: [],
presetConfig: {
gqlTagName: "gql",
},
},
},
ignoreNoDocuments: true,
};
export default config;
Agreed, it takes a little bit more of the server resources to run another endpoint, but it’s a small price to pay for the convenience (and security) that you get.
It still feels like a hack, so if you have a better solution, please let me know.
Written by Arun kumar Gandlur on