8
0

More than 1 year has passed since last update.

GraphQLのディレクティブについて

Last updated at Posted at 2021-12-05

概要

GraphqlのdirectiveについてやCustom directiveの導入方法のまとめ

ディレクティブとは

GraphQLのtype, field, 引数などに付与するデコレータで、必要に応じてカスタムロジックを実行できます。

例えばGraphQLには@deprecatedというディレクティブが組み込まれていて、装飾した箇所が非推奨だと知らせることができます。

type User {
  name: String
  age: Int
  gender: String @deprecated(reason: "このようにコメントを付与できます")
}

type Query {
  user: User
}

Playground
スクリーンショット 2021-12-06 1.07.26.png

他には@skip@includeなどがある
Playground
スクリーンショット 2021-12-06 1.45.04.png

ディレクディブ 内容
@deprecated 型の非推奨フィールドや非推奨の列挙値など
@skip 条件付きでクエリに含めないことができます。
@include 条件付きでクエリに含めることができます。

カスタムディレクティブ

ディレクティブを独自に定義し、付与できます。
使用するライブラリーごとに実装方法が少し違っているので注意が必要です。

Apolloによるスキーマファーストでの実装例

nestjsの例

TypeGraphQLの例

サンプル

@authというリクエストのトークンを取得しトークン認証をするカスタムディレクティブ

authDirective.ts
const authDirectiveTransformer = (
  directiveName: string
) => {
  return {
    authDirectiveTypeDefs: `directive @${directiveName} on FIELD_DEFINITION`,
    authDirective: (schema: GraphQLSchema) => mapSchema(schema, {
      [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
        const directive = getDirective(
          schema,
          fieldConfig,
          directiveName
        )?.[0];

        if (directive) {
          const originalResolve = fieldConfig.resolve || defaultFieldResolver;
          fieldConfig.resolve = async function (
            source,
            args,
            context,
            info
          ) {
            // contextの情報が取得できる
            const token = context.token;
            // トークンチェックなど...
            const isAuthorized = false
            if (!isAuthorized) {
              throw new Error("Unauthrized");
            }

            return originalResolve(source, args, context, info)
          };
          return fieldConfig;
        }
      }
    })
  }
};
index.ts
const typeDefs = gql`
  type Address {
    region: String
    city: String
  }

  type User {
    name: String
    age: Int
    gender: String @deprecated(reason: "このようにコメントを付与できます")
    address: Address 
  }

  type Query {
    user: User @auth
  }
`;

const resolvers = {
  Query: {
    user: () => ({
      name: "taro",
      age: 25,
      gender: "male",
      address: {
        region: "tokyo",
        city: "shibuya"
      }
    })
  },
};

const { authDirective, authDirectiveTypeDefs } = authDirectiveTransformer("auth")
const executableSchema = makeExecutableSchema({
  typeDefs: [
    authDirectiveTypeDefs,
    typeDefs
  ],
  resolvers,
});
const schema = authDirective(executableSchema)
const server = new ApolloServer({
  schema,
  context: ({ req }) => {
    return {
      token: req.headers["authentication-token"] || "",
    };
  },
  plugins: [ApolloServerPluginLandingPageGraphQLPlayground()]
});

Playground
スクリーンショット 2021-12-06 2.53.40.png

おわりに

今回は認証しかカスタムディレクティブを使用しませんでしたが、他にこういったことで使うといいよってのがありましたらぜひ教えていただきたいです!

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0