Directives
Directives are @-prefixed annotations on operations or schema definitions. @include, @skip, @deprecated ship in the spec; servers add their own (@auth, @cacheControl, @constraint).
Built-in + custom directives
EXAMPLE
# 1) Operation-level directives — @include / @skip
query UserProfile($id: ID!, $withPosts: Boolean!) {
user(id: $id) {
id
name
posts @include(if: $withPosts) {
title
}
followers @skip(if: $withPosts) {
count
}
}
}
# 2) Schema directive — @deprecated
type User {
name: String!
email: String!
fullName: String! @deprecated(reason: "Use 'name' instead")
}
# 3) Custom schema directive — @auth
directive @auth(requires: Role = USER) on FIELD_DEFINITION
enum Role { ADMIN, USER, GUEST }
type Query {
me: User! @auth
secrets: [String!]! @auth(requires: ADMIN)
public: String
}
# Apollo Server v4 — custom directive implementation
import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils';
function authDirectiveTransformer(schema) {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const dir = getDirective(schema, fieldConfig, 'auth')?.[0];
if (!dir) return;
const { requires } = dir;
const { resolve } = fieldConfig;
fieldConfig.resolve = (src, args, ctx, info) => {
if (!ctx.user) throw new Error('Unauthenticated');
if (requires === 'ADMIN' && ctx.user.role !== 'ADMIN') {
throw new Error('Forbidden');
}
return resolve(src, args, ctx, info);
};
return fieldConfig;
},
});
}
# 4) @cacheControl — Apollo's response caching
type Post @cacheControl(maxAge: 60) {
id: ID!
title: String!
body: String! @cacheControl(maxAge: 300)
}
# 5) Validation directives — @constraint (graphql-constraint-directive)
type Mutation {
signup(
email: String! @constraint(format: "email")
password: String! @constraint(minLength: 8, maxLength: 72)
age: Int! @constraint(min: 13, max: 120)
): User!
}
Why it matters
Custom directives push cross-cutting concerns (auth, rate-limit, caching) out of resolvers and into the schema. Readers see the policy on the field itself, not buried in 40 lines of boilerplate.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Built-ins: @include @skip @deprecated
type User { email: String @deprecated(reason: "use contact.email") }
Try it Yourself »
Discussion
Loading…