graphql
graphql copied to clipboard
Generate graphql operations (code first)
Current behavior and motivation
We can generate schema.graphql
which is great.
Although in order to generate Angular sdk library to better communicate with NestJS all of the code-generator tools I've found are much like https://github.com/dotansimha/graphql-code-generator - they require operations graphql schema files which unfortunatelly have to be created manually, i.e.:
query someQuery {
someQuery {
result
}
}
That leads to redundancy, errors and slower development process.
Expected behavior
Add functionality to generate optional operations.graphql
file with graphql queries and mutations instead of inputs and types (which are in schema.graphql
).
GraphQLModule.forRoot({
...
autoSchemaFile: `schema.graphql`,
// That would solve all the world's problems.
autoOperationsSchemaFile: `operations.graphql`,
...
}),
Hey, same here for React App, we would like to generate GraphQL operation from code first resolver (with annotation) but seems not included to GqlModuleOptions
so far. Any idea on this?
I wrote a custom document loader for graphql-code-generator which will automatically generate operations from graphql schema.
This is my codegen.yml
schema: "http://localhost:3000/graphql"
overwrite: true
documents:
- "http://localhost:3000/graphql":
loader: ./operationsFromSchemaGenerator.js
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-vue-apollo
config:
withCompositionFunctions: true
vueCompositionApiImportFrom: vue
dedupeOperationSuffix: true
and this is operationsFromSchemaGenerator.js
:
const {
getIntrospectionQuery,
parse,
buildClientSchema,
print,
} = require("graphql");
const { buildOperationNodeForField } = require("@graphql-tools/utils");
const axios = require("axios").default;
async function getSchemaFromUrl(url) {
const response = await axios
.post(url, { query: getIntrospectionQuery().toString() })
.catch((e) => console.log(e));
return buildClientSchema(response.data.data);
}
module.exports = async function(schemaUrl) {
const schema = await getSchemaFromUrl(schemaUrl);
const operationsDictionary = {
query: { ...(schema.getQueryType()?.getFields() || {}) },
mutation: { ...(schema.getMutationType()?.getFields() || {}) },
subscription: { ...(schema.getSubscriptionType()?.getFields() || {}) },
};
let documentString = "";
for (const operationKind in operationsDictionary) {
for (const operationName in operationsDictionary[operationKind]) {
const operationAST = buildOperationNodeForField({
schema,
kind: operationKind,
field: operationName,
});
documentString += print(operationAST);
}
}
return parse(documentString);
};
It is not fancy, but it works for my use-case. Feel free to customize it for your needs.
@Zippersk very cool, worked for me for angular with configuration as below:
schema: 'http://localhost:3000/graphql'
overwrite: true
documents:
- 'http://localhost:3000/graphql':
loader: ./operations-from-schema.generator.js
generates:
./sdk.ts:
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-apollo-angular':
sdkClass: true
serviceName: Api
And this is my operations-from-schema.graphql.ts file (refactored to TypeScript, for in safety, post -> get etc. and I use got library over axios):
import { buildClientSchema, getIntrospectionQuery, parse, print } from 'graphql';
import { buildOperationNodeForField } from '@graphql-tools/utils';
import got from 'got';
const getSchemaFromUrl = async (url: string) => {
const searchParams = {
query: getIntrospectionQuery().toString(),
};
const response = await got.get(url, {
searchParams,
responseType: `json`,
});
const { data } = response.body as any;
return buildClientSchema(data);
};
const main = async (schemaUrl: string) => {
const schema = await getSchemaFromUrl(schemaUrl);
const operationsDictionary = {
query: { ...(schema.getQueryType()?.getFields() ?? {}) },
mutation: { ...(schema.getMutationType()?.getFields() ?? {}) },
subscription: { ...(schema.getSubscriptionType()?.getFields() ?? {}) },
};
let documentString = ``;
for (const [operationKind, operationValue] of Object.entries(operationsDictionary)) {
for (const operationName of Object.keys(operationValue)) {
const operationAST = buildOperationNodeForField({
schema,
kind: operationKind as any,
field: operationName,
});
documentString += print(operationAST);
}
}
return parse(documentString);
};
export default main;
Usage
npx tsc ./operations-from-schema.generator.ts && npx graphql-codegen
@rradarsu The script above works great, however it doesn't generated fragments from what I can tell.
Without this code-first seems incomplete.
I think if there are no plans to add this feature any time soon, this issue should be reopened https://github.com/nestjs/graphql/issues/937
Unless there is some other non-hacky workaround for this.
@mchaliadzinau this feature doesn't seem to be required for the code-first approach