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

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

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

https://dev.classmethod.jp/articles/graphql-dataloader-sample/

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

# ハマった内容
### グラフモデルの生成
schemaを以下のように記述し、gqlgenしました。

```graphql: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が生成されます。

```go: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を導入したいです。
データローダーのためにカスタムモデルを使用します。

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

https://gqlgen.com/getting-started/#dont-eagerly-fetch-the-user

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

```diff_go: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`をモデルのファイルに宣言します。
また、ドメインオブジェクト生成のためのコンストラクタの定義も行いました。

```go: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を再度実行
以下のエラーが出てしまいました。

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

# 以下省略
```

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

https://github.com/99designs/gqlgen/issues/693#issuecomment-625457628

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

```go:models_gen.go
package graph

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

```go:model.go
package model

// 省略

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

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

```diff_graph_ql: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!
}
```

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