先々週 や 先週 のブログで書いた自分専用Todoアプリが、バックエンドに使っているRedmineのバージョンを上げたら動かなくなってしまいまいました。😅
その対処でしみじみとGraphQLの良さを感じたので書きます。
Redmine API
RedmineはAPIをサポートしています。自分専用TodoアプリはこのREST APIを使いRedmineのチケット(Issues)APIでIssues情報の取得・変更を行っています。
Redmine APIはリソースによりAlpha, Betaバージョンのものもありますが、Issuesはバージョン3.4からStable(安定版)サポートされていました。Issues APIのドキュメントを見てわかるように、比較的ゆるい仕様の定義です。自分専用Todoアプリを作るときも、APIの戻り値のJSONを解析しながら作りました。
REST APIにも OpenAPI(Swagger の進化形)のように明確なREST APIの仕様書記述フォーマットも用意されていますが、どれくらい使われているのでしょうか?
EY-OfficeのRuby on Rails API入門コース ではOpenAPIにふれていますが・・・
Redmineのカスタムフィールド
Redmineのタスク(チケット、Issues)管理の項目にはタイトル、説明、ステータス、優先度・・・などの最初からある項目以外に、独自のカスタムフィールドを追加することができます。
カスタムフィールドは文字列、数値、論理値、選択肢・・・などの型があり、プロジェクト単位で設置できます。先週 書いたアプリの機能のタスクは特別なチケットなのでSpecal(安易な名付け😅)という論理(Boolean)のカスタムフィールドを追加しました。
バージョン3.4から4.1へのAPI変更点
バージョン3.4
さて今回の問題ですが、Redmineバージョン3.4のIssues APIの戻り値の型をGraphQLの型で記述すると以下のようになっていました(一部推論も含んでいます)。
カスタムフィールドは複数持てるのでIssueの中ではCustomFieldの配列です、ただしカスタムフィールド存在しない場合はバージョン3.4ではNULL(custom_fields項目が存在しない)になっていました。
また、CustomField要素のオブジェクト型の要素id, name, valueはすべてNULLではない(必須の)項目でした。
注) GrapthQLの型定義で!
が付いている項目はNULLではない(必須)項目です。
type Issue {
id: Int!
project: IdName!
tracker: IdName!
status: IdName!
priority: IdName!
author: IdName!
assigned_to: IdName!
subject: String!
description: String
start_date: Date!
due_date: Date
done_ratio: Float!
is_private: Boolean!
estimated_hours: Int!
custom_fields: [CustomField] // ← カスタムフィールド
created_on: DateTime!
updated_on: DateTime!
closed_on: DateTime
}
type CustomField { // ← カスタムフィールドの要素の型
id: Int!
name: String!
value: String!
}
type IdName {
id: Int!
name: String!
}
バージョン4.1
バージョン4.1で変わったところにみ書くと以下のようになりました(ここではプロジェクトにカスタムフィールドがある場合のみを書いてます)。
バージョン4.1では、Specalカスタムフィールドが設定されてないタスクでもcustom_fieldsが設定されるようになりました。だたしカスタムフィールドの設定されてない、CustomFieldオブジェクトのvalueはNULLになります。
今回iOSアプリが動かなくなった原因は、このvalueがNULLになるようなSwift Recordの定義なになっていたため、JSON読み込みライブラリーでエラーが発生していました。
type Issue {
・・・
custom_fields: [CustomField]! // ← ! が付きました
・・・
}
type CustomField {
id: Int!
name: String!
value: String // ← ! が無くなりました
}
まとめ
少し前にGraphQLのバックエンドを作っていたこともあり、もしRedmineのAPIがGraphQLだったら今回のようなNULLの問題は起きなかったに違いありません。
ちなみに、Issues APIのドキュメントの履歴をみてみましたが今回の変更に付いては書かれていませんでした。ドキュメントベースのREST APIではNULLの扱いは、なおざりになりがちです。
GraphQLのメリットととしては、
- 複数の関連情報が一度に取得できる
- 取得項目を設定できるので不要な情報を取得しなく良い
- バージョンアップでの互換性が保ちやすい
などが語られています。
しかし、データの型が明確に定義されていることも重要なメリットではないかと、今回の問題対処で実感しました。