📑
[ios] Apollo Codegenで別々のOperationを同じObjectとして扱う方法
apollo codegenで同じSchemaに対して同じ結果セットが返ってくる、別々のQueryをGenerateすると別名Objectが生成される。
Swiftで同じ構造だけども、別々のObjectとして認識されてしまうとコードが冗長になるのでどうにか回避したい。
todoAPI
query Todo {
todo {
id
name
...
}
}
todo1API
query Todo1($name: name!) {
todo({where: {name: {"_eq": $name}}}) {
id
name
...
}
}
取得する中身が一緒でも別々のQueryOperationとして判別される。
apollo codegen:generate すると
- TodoQuery Class
- Todo1Query Class
ができあがる。別ファイルに吐き出されるので、同じClass(Operation名は付けられない...)
最初にやったこと
if文で分岐。受取側のMethodを複数用意してオーバーロードで区別する
codeA
// 結果セットは同じ。Classが違うだけ
var todo: TodoQuery.Data.Todo?
var todo1: Todo1Query.Data.Todo?
// なんとかしてセットされているクラスを見分ける。
if ('todo == TodoQuery') {
obj.setTodo(todo as! TodoQuery.Data.Todo)
} else if ('todo == Todo1Query') {
obj.setTodo(todo as! Todo1Query.Data.Todo)
}
class obj {
func setTodo(todo: TodoQuery.Data.Todo) {...}
func setTodo(todo: Todo1Query.Data.Todo) {...}
}
まぁ、分岐がすくないうちはまだいいかもだけど(初心者コード丸出しだけど...) スマートじゃない…
次にやってこと
引数の型をprotocolにしてまとめて受け入れてみる
codeB
protocol pTodo {}
extension TodoQuery.Data.Todo: pTodo {}
extension Todo1Query.Data.Todo: pTodo {}
// 結果セットは同じ。Classが違うだけ
var todo: TodoQuery.Data.Todo?
var todo1: Todo1Query.Data.Todo?
// 引数の型がprotocolなのでextensionしている型は受け入れる
obj.setTodo(todo)
obj.setTodo(todo1)
class obj {
func setTodo(todo: pTodo) {...}
}
受け入れることはできた。ただ setTodo method 内の処理でPropertyアクセスがうまくできなかった。
あくまでも protocol pTodo
なので pTodo として定義してある必要があったのだ
extensionで拡張(Replace)してみよう
codegensされたClassObjectそのものを拡張してreplace してしまえばいいのでは?
と考えてみました。
codeV
extension Todo1Query.Data.Todo {
func replaceClass() -> TodoQuery.Data.Todo {
// 同じ結果セットなので、resultMapをreplaceしちゃう!
return TodoQuery.Data.Todo(unsafeResultMap: self.resultMap);
}
}
// 結果セットは同じ。Classが違うだけ
var todo: TodoQuery.Data.Todo?
var todo1: Todo1Query.Data.Todo?
// TodoQuery.Data.TodoにReplace
var rTodo: TodoQuery.Data.Todo = todo1.replaceClass()
setTodo(todo)
setTodo(rTodo)
class obj {
func setTodo(todo: TodoQuery.Data.Todo) {...}
}
ちゃんと動きました!これで同じ結果セットのObjectClassを揃えることに成功!
TodoQuery.Data.Todo を拡張すれば更に色々と共通処理がかけるようになります。
※ サンプルコードは 適当に記述しています。このままでは動きません…
ほかにスマートな方法があればぜひ教えていただきたいです。
最後まで読んでいただきありがとうございました!
Discussion