LoginSignup
0
0

gqlgenでカスタムモデルを使った際に panic: interface conversion でハマった話

Posted at

概要

DataLoaderを使うためにgqlgenにカスタムモデルを導入した際、
gqlgenpanic: interface conversionエラーが発生したので、その解決の記録を残します。

DataLoaderってなんやねん って方は以下がわかりやすいです。
簡単にいうと、N+1問題を避けるためにバッチ処理を使って効率的にデータを取得しようってことみたいです。

おことわり

  • 筆者はBE1年目の駆け出しGopherです。
  • 表現に曖昧な箇所や不正確な箇所があるかもしれませんがご容赦ください。

ハマった内容

グラフモデルの生成

schemaを以下のように記述し、gqlgenしました。

schema.graphqls
type User {
  id: ID!
  name: String!
  department: Department!
}

type Department {
  # 省略
}

type Query {
  users: [User!]!
}

input NewUser {
  name: String!
  deparmentId: ID!
}

type Mutation {
  createUser(input: NewUser!): User!
}

以下のようなmodelが生成されます。

models_gen.go
package graph

type User struct {
    ID           uint64     `json:"id"`
    Name         string     `json:"name"`
    Department   Department `json:"department"`
}

type Department struct {
    // 省略
}

type NewUser struct {
    Name         string `json:"name"`
    DepartmentID uint64 `json:"departmentId"`
}

カスタムモデルの導入

Userをバルクで取得した際のN+1問題を避けるために、DataLoaderを導入したいです。
データローダーのためにカスタムモデルを使用します。

カスタムモデルについては以下を参照してください。

まずは先ほど生成したグラフモデルからUserを削除します。

models_gen.go
package graph

- type User struct {
- 	ID           uint64     `json:"id"`
-	Name         string     `json:"name"`
-	Department   Department `json:"department"`
- }

type Department struct {
    // 省略
}

type NewUser struct {
    Name         string `json:"name"`
    DepartmentID uint64 `json:"departmentId"`
}

上で削除したUserをモデルのファイルに宣言します。
また、ドメインオブジェクト生成のためのコンストラクタの定義も行いました。

model.go
package model

import (
    // 省略
)

type User struct {
    ID           uint64 `json:"id"`
    Name         string `json:"name"`
    DepartmentID uint64 `json:"departmentId"` // dataloaderのためidを指定
}

type UserDescription struct {
    Name         string
    DepartmentID uint64
}

// Userのコンストラクタを定義
func NewUser(desc UserDescription) *User {
    return &User{
        Name:         desc.Name,
        DepartmentID: desc.DepartmentID,
    }
}

gqlgenを再度実行

以下のエラーが出てしまいました。

go1.21.1 run github.com/99designs/gqlgen@v0.17.39 generate --verbose
panic: interface conversion: types.Type is *types.Signature, not *types.Named

# 以下省略

解決法

こちらのコメントが参考になりました。

GQLタイプと同名の関数が存在していたことでエラーが発生していたようです。

models_gen.go
package graph

type NewUser struct {
    Name         string `json:"name"`
    DepartmentID uint64 `json:"departmentId"`
}
model.go
package model

// 省略

// Userのコンストラクタを定義
func NewUser(desc UserDescription) *User {
    return &User{
        Name:         desc.Name,
        DepartmentID: desc.DepartmentID,
    }
}

スキーマを以下のように変更して重複をなくすと、エラーが発生しなくなりました。

schema.graphqls
type User {
  id: ID!
  name: String!
  department: Department!
}

type Department {
  # 省略
}

type Query {
  users: [User!]!
}

- input NewUser {
+ input UserCreateInput {
  name: String!
  deparmentId: ID!
}

type Mutation {
-  createUser(input: NewUser!): User!
+  createUser(input: UserCreateInput!): User!
}

感想

一度気づくと「なぜ気づかなかったのだろう」となりますが、エラーメッセージからだと結構気づきづらいなと感じました。(小並感)

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