0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring for GraphQL TIPS〜部分更新したい〜

Posted at

はじめに

ブログを更新するAPIを想像してください。
あなたは、ブログの記事タイトルだけを更新したいとします。
でもAPIの仕様によっては、タイトルだけじゃなく本文とかも全部送らないといけないことがありえます。
「変えたいのはタイトルだけなのに他のフィールドも送らなきゃなのはナンセンス」って考えたりしませんか?

また他にも新しいフィールドが追加されたときに生じる問題もあります。
たとえば、予約投稿のためにscheduledPublishDateというフィールドを追加したとします。
古いクライアントはその存在を知らないので送ってきません。
でもサーバーが「フィールドが送られてこなかった=nullで更新」と解釈すると、
意図せずscheduledPublishDateの値が消えるという事故が起きます。

これを防ぐには、「送られてきたフィールドだけを更新する」ための部分更新の仕組みが必要です。
つまり、RESTでいうPATCH相当のことをGraphQLでもやりたい、という話です。

なお、動くサンプルコードも用意しています。

Spring for GraphQLでどうやるのか

GraphQLでは、更新対象外のフィールドをundefinedで表現する事が可能です。
ここで重要なのは、サーバー側がundefinedを識別して、「undefinedのフィールドは変更しない」ように実装することです。

ArgumentValuenullundefinedを区別する

Spring GraphQLのArgumentValue<T>を使うことで実現できます。
このクラスを使うことで以下の3つの状態を区別可能になります。

状態 説明 処理
undefined リクエストに含まれていない 更新対象外
null 明示的に送られた 値を削除
リクエストに含まれている 値を更新

このように分けて扱えるようにすることで、更新・削除・対象顔のフィールドを明示的に区別できます。

Inputの定義

記事編集用のInputはこのようになります。

data class EditArticleInput(
    @field:NotNull
    val articleId: UUID?,

    val title: ArgumentValue<
        @NotBlank
        @Size(min = 3, max = 100)
        String
    >,

    val content: ArgumentValue<
        @NotBlank
        @Size(min = 10, max = 5000)
        String
    >,

    val scheduledPublishDate: ArgumentValue<LocalDateTime?>
) {
    val articleIdAsNotNull by lazy { articleId!! }
}

各フィールドを ArgumentValue でラップすることで、「送られてきたか?」「nullか?」「値があるか?」を区別可能になります。

Beanバリデーション

バリデーションもちゃんと効きます。
たとえば@NotBlank@SizeArgumentValueのジェネリクスの中に書いておけば、 値が送られてきたときだけバリデーションされるようになります。

undefinedのときはバリデーションはスキップされます。

まとめ

ArgumentValueを使うと、Spring for GraphQLでも以下のことが実現できました。

  • 更新したいフィールドだけ送る
  • 送られてこなかったフィールド(undefined)はそのまま保持
  • nullのときは削除する
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?