patterntypescriptgraphqlModerate
GraphQL directives — @deprecated for fields and custom directives for cross-cutting concerns
Viewed 0 times
@graphql-tools/utils 10.x
directives@deprecatedcustom directiveschema transformationmapSchemaauth directive
Error Messages
Problem
Removing fields from a GraphQL schema is a breaking change. Cross-cutting concerns like auth, rate limiting, and formatting are copy-pasted into every resolver instead of being centrally managed.
Solution
Use
@deprecated for safe field deprecation. Implement custom schema directives for cross-cutting concerns.type User {
email: String!
username: String @deprecated(reason: "Use email field instead")
}
# Custom directive
directive @auth(requires: Role!) on FIELD_DEFINITION
directive @rateLimit(max: Int!, window: String!) on FIELD_DEFINITION
type Query {
adminData: SensitiveData @auth(requires: ADMIN)
search(q: String!): [Result!]! @rateLimit(max: 100, window: "1m")
}// Implement with @graphql-tools/schema and mapSchema
import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils';
function authDirectiveTransformer(schema: GraphQLSchema) {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD](fieldConfig) {
const directive = getDirective(schema, fieldConfig, 'auth')?.[0];
if (!directive) return fieldConfig;
const { resolve = defaultFieldResolver } = fieldConfig;
return {
...fieldConfig,
resolve: async (source, args, ctx, info) => {
if (!ctx.user?.roles.includes(directive.requires)) {
throw new GraphQLError('Forbidden', { extensions: { code: 'FORBIDDEN' } });
}
return resolve(source, args, ctx, info);
},
};
},
});
}Why
@deprecated is recognized by tools and clients — GraphiQL shows warnings, codegen marks fields as deprecated in TypeScript. Custom directives keep resolver code clean and let policy changes be applied schema-wide.Gotchas
- @deprecated does not remove the field — clients can still request it until you physically remove it
- Custom directives in Apollo Server 4+ require schema transformation — they are not applied automatically
- Directive arguments must be valid input types — no object types
- Federation subgraphs must redeclare custom directives in each subgraph that uses them
Context
Schema design for deprecation and applying cross-cutting concerns declaratively
Revisions (0)
No revisions yet.