LoginSignup
5
5

More than 3 years have passed since last update.

Custom Scalar実装(GraphQL-SpringBoot)

Posted at

はじめに

GraphQLには標準のスカラー(Boolean, Int, Float, String, ID)のほか、独自に定義した任意のスカラーを使用することができる。Javaでの実装について調査しデモを作成したものをまとめた。1

実装

スキーマ定義

  • カスタムスカラーを宣言する
  • 標準スカラーと同様に変数の型として使用する
scalar ISODate

type Member {
    memberId: ID!
    name: String!
    age: Int
    birthday: ISODate
}

DTO作成

typeに対応するDTOクラスを作成する

import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class Member {
    private String memberId;
    private String name;
    private Integer age;
    private LocalDate birthday;
}

変換定義実装

  • スカラー名と変換定義の組み合わせを示すGraphQLScalarTypeインスタンスを作成する(シングルトン)
    • nameにはスキーマで宣言したスカラー名を登録する
    • coercingには変換定義を実装したインスタンスを登録する
  • 変換定義はCoercingインターフェースをimplmentsする
    • 今回はJava側のjava.time.LocalDateをGraphQLのISODate(実体は文字列)としてレスポンスに返すので、Coercingの仮型パラメータの"I"にLocalDateを"O"にStringをそれぞれ指定する。
import java.time.LocalDate;
import graphql.language.StringValue;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;

public class ISODateScalar {

    public static final GraphQLScalarType singleton = GraphQLScalarType.newScalar(
            ).name("ISODate") // scalar名
            .coercing(new ISODateCoercing()) // 変換定義
            .build();

    // 変換定義の実装
    private static class ISODateCoercing implements Coercing<LocalDate, String> {

        @Override
        public String serialize(Object dataFetcherResult) throws CoercingSerializeException {
            if (dataFetcherResult instanceof LocalDate) {
                return dataFetcherResult.toString();
            }
            throw new CoercingSerializeException(dataFetcherResult + " is NOT LocalDate!");
        }

        @Override
        public LocalDate parseValue(Object input) throws CoercingParseValueException {
            try {
                return LocalDate.parse(input.toString());
            } catch (Exception e) {
                throw new CoercingParseValueException(e);
            }
        }

        @Override
        public LocalDate parseLiteral(Object input) throws CoercingParseLiteralException {
            try {
                return LocalDate.parse(((StringValue) input).getValue());
            } catch (Exception e) {
                throw new CoercingParseLiteralException(e);
            }
        }

    }
}

serializeはJavaの外にデータを送る際に使用される。なのでLocalDateStringの変換を実装する。

parseLiteralはJavaの中にデータを取り込む際に使用される。なのでStringLocalDateの返還を実装する。ただし、引数にはgraphql.language.StringValue(文字列の場合2)でラップされた状態で渡されるため、getValueによりStringインスタンスを取り出す処理を挟む必要がある。

parseValueはいつ呼び出されるのかよくわからなかった……(教えてください)。公式のドキュメントを見る限りラップされていないインスタンスが渡される模様。

変換定義登録

上で作成したシングルトンをBeanとして登録する。

@Configuration
public class ExtendedScalarConfiguration {
    @Bean
    public GraphQLScalarType isoDate() { // メソッド名は任意
        return ISODateScalar.singleton;
    }
}

参考サイト


  1. 本稿作成時点では公式のサンプルがdeprecatedなコンストラクタを使っていたのでそれを回避する方法を調べた 

  2. 整数, 真偽値でリクエストが投げられた場合はそれぞれIntValue, BooleanValueのインスタンスが渡される。 

5
5
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
5
5