graphql-weaver
graphql-weaver copied to clipboard
How to rename fields properly?
I want to camelize field and argument names, I thought it was simple, just renaming the snake-style fields to camel-style. So I wrote a custom module as the following:
export class SnakeToCamelFieldModule implements PipelineModule {
private snakeToCamelFieldSchema = new SnakeToCamelFieldSchema();
transformSchema(schema: GraphQLSchema): GraphQLSchema {
return transformSchema(schema, this.snakeToCamelFieldSchema);
}
}
function isSpecificCase(s: string, converter: (value: string, locale?: string) => string ) {
return s === converter(s);
}
class SnakeToCamelFieldSchema implements SchemaTransformer {
private convertMap: { [key: string]: string; } = {};
transformField(field: GraphQLNamedFieldConfig<any, any>, context: any) {
// Rename a field in a type
if (isSpecificCase(field.name, snakeCase)) {
const camelName = camelCase(field.name);
this.convertMap[camelName] = field.name;
return {
...field,
name: camelName
};
}
return field;
}
renameField(name: string): string {
return this.convertMap[name] || name;
}
}
The schema was exactly what I want, but I also need to rename the query back. Then I updated FieldNode
's name
, but it failed and I got Failed to determine type of SelectionSet node
. It seems like some validations called before executing the query.
Then I thought maybe graphql aliases
could help, so I updated the code as the following:
export class SnakeToCamelFieldModule implements PipelineModule {
private snakeToCamelFieldSchema = new SnakeToCamelFieldSchema();
transformSchema(schema: GraphQLSchema): GraphQLSchema {
return transformSchema(schema, this.snakeToCamelFieldSchema);
}
transformQuery(query: Query): Query {
const definitions: Array<OperationDefinitionNode> = query.document.definitions.filter(
(e: DefinitionNode): e is OperationDefinitionNode => e.kind === "OperationDefinition");
const fieldNodes = flatten(definitions.map(def => collectFieldNodes(def)));
fieldNodes.map((field: any) => {
const originalName = this.snakeToCamelFieldSchema.renameField(field.name.value);
if (originalName !== field.name.value) {
field.alias = {
kind: "Name",
value: field.name.value
};
field.name.value = originalName;
}
});
return query;
}
}
It only partly succeeded, no errors occured this time, some queries like { getUsername }
succeeded, it returned { "data": { "getUsername": "haofuxin" } }
. But some queries like
{
relay {
routes {
edges {
node {
isActive
id
}
}
}
}
returned
{
"data": {
"relay": {
"routes": {
"edges": [
{
"node": {
"id": "Um91dGUtYXNjZW5kXzE2NA=="
}
}
]
}
}
}
}
isActive
was missing. After diving in for a while, I found that isActive
was filtered out in https://github.com/graphql/graphql-js/blob/ed74228dc8540e3d2681cb6da473e7ce5edb7850/src/execution/execute.js#L649-L655 . fieldName
is is_active
rather than isActive
.