🛰️

GraphQL Scalars便利だなぁ🚀

2022/09/01に公開

こんにちは、yunbooです。

今回はThe Guildという組織が開発しているGraphQLエコシステムのGraphQL Scalarsについての記事です。

余談なんですが、The Guildは今回紹介するGraphQL Scalars以外にも様々なエコシステムを提供しており、その代表格としてはGraphQL Code Generatorがあると思います。
他にも、たくさん便利なものを提供しているので、もろもろ見てみると役に立つ情報が得られたり、面白いと思います。

さて、本題ですがGraphQL Scalarsについて説明する前の前提知識として、GraphQLのScalar型について軽く説明します。

Scalar型とは

GraphQLにはスキーマを定義する際に型が存在しますが、Scalar型とは

  • プリミティブな値を表すもの
  • フィールドが最終的に変換される、それ以上に分割出来ない型

GraphQLがデフォルトで用意しているのは、

  • Int: 符号付き 32 ビット整数
  • Float: 浮動小数点値
  • String: UTF-8 文字シーケンス
  • Boolean: true or false
  • ID: オブジェクトの一意な識別子

の5つです。
さらに、よりスキーマの表現力を広げるために、Custom Scalarというのもあります。

Custom Scalar

先ほどの5つでほとんどのユースケースに対応はできますが、Custom Scalar型を使いより強力な型チェックや検証ができるようになります。

例えば、Custom Scalarの例として、Email型で紹介します。

クライアントがフォームでメールアドレスを入力し、入力された値に対しバリデーションで、文字列がが正しいメールアドレスの形式なのか確認します。

バリデーションを経て正しい形でクライアントからGraphQLサーバーにMutationで送信します。

この際に、スキーマにemail: String!で定義していると正しい形式で送られてきているメールアドレスの情報が失ってしまい、ただのString型になってしまいます。

input LoginInput {
  email: String! <-- ここ
  password: String!
}

type Mutation {
  login(input: LoginInput!): LoginPayload
}

ここで、email: Email!と定義してあればGraphQLでも正しくチェックし適切な情報をサーバーに送ってくれます。

input LoginInput {
  email: Email! <-- ここ
  password: String!
}

type Mutation {
  login(input: LoginInput!): LoginPayload
}

他にもCustom Scalarのいいところで、今回の説明だとemailというフィールド名なので、仮にString型だとしてもメールアドレスであることは見てわかると思いますが、例えばidフィールドを持った場合に、連番のidなのか、それともまた違ったidの形式なのかわからないと思います。
ですが、id: UUID!であればこのidはID型という抽象的な型ではなく、UUID型より具体な型だとスキーマから型名だけで意図を伝えることもできます。

Custom Scalarを使いよりスキーマの表現の幅を広げることができるようになりました。
ただ、デフォルトで用意されている訳ではないのでCustom Scalarを一から自分で実装する必要があります。
実装自体にはそれなりのコストが掛かってきます。

そこで、GraphQL Scalarsの出番です。

GraphQL Scalarsとは

様々なユースケースに沿ったCustom Scalarのライブラリです。
先ほどの説明で使用したメールアドレスのCustom Scalarももちろん用意されています。

https://www.graphql-scalars.dev/docs/scalars/email-address

他にもUUIDであったり、JWTなど幅広く用意されています。
興味ある方はドキュメントのScalarsの所を見てもらえればなと思います。

今度は逆にCustome Scalarで定義した型をクライアント側でも使いたいと思います。
そこは、現状だとスキーマを見てGraphQL Code Generatorがよしなにやってくれるわけではなくて(自分が知っている限りだと)、以下のようにTypeScriptで独自の型を実装しGraphQL Code Generatorのプラグインを使いつつ当てはめていく必要があります。

export type EmailAddress = string & { __type: "EmailAddress" };

export const isEmailAddress = (
  str: string
): str is EmailAddress => {
  const EMAIL_ADDRESS_REGEX =
    /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;

  return EMAIL_ADDRESS_REGEX.test(str);
};

こちらに関しては、下の記事で、より詳細な説明がされいるので参考になりました🙋‍
https://www.wantedly.com/companies/wantedly/post_articles/387161

ただ、自作するのは多少めんどくさい部分でもあるので今後GraphQL Code Generatorがプラグインなどを用意してくれることに期待しています。。。

最後に

GraphQL Scalarsの説明というより、Custom Scaralsの説明のが長々としてしまいましたが、そのCustom Scaralsを使うためにGraphQL Scalarsを使うと便利だよというのが今回伝えたかったことでした。

Discussion