はじめに
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
をそれぞれ指定する。
- 今回はJava側の
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の外にデータを送る際に使用される。なのでLocalDate
→String
の変換を実装する。
parseLiteral
はJavaの中にデータを取り込む際に使用される。なのでString
→LocalDate
の返還を実装する。ただし、引数にはgraphql.language.StringValue
(文字列の場合2)でラップされた状態で渡されるため、getValue
によりString
インスタンスを取り出す処理を挟む必要がある。
parseValue
はいつ呼び出されるのかよくわからなかった……(教えてください)。公式のドキュメントを見る限りラップされていないインスタンスが渡される模様。
変換定義登録
上で作成したシングルトンをBeanとして登録する。
@Configuration
public class ExtendedScalarConfiguration {
@Bean
public GraphQLScalarType isoDate() { // メソッド名は任意
return ISODateScalar.singleton;
}
}
参考サイト
- GraphQLって何? - Qiita
- GraphQL Java - Scalar
- graphql-java/graphql-java-extended-scalars
- Spring Boot 2 / GraphQL Extended Scalars not working: Exception “Cannot construct instance” “cannot deserialize”