gqlgen generate后仍404是因为它只生成类型和接口,不注册HTTP路由;必须手动将handler.NewDefaultServer封装为gin.HandlerFunc并挂载到Gin路由(如router.POST("/graphql", GraphqlHandler())),且路径需与前端请求一致。

gqlgen generate 后为什么还是 404?
因为 gqlgen 只生成 Go 类型和 resolver 接口,不注册任何 HTTP 路由——它根本没碰 net/http 或 gin.Engine。你看到的 server.go 骨架默认用的是 http.DefaultServeMux,跟 Gin 完全无关。
必须手动把 handler.NewDefaultServer 封装成 gin.HandlerFunc,再挂到 Gin 路由上:
import (
"github.com/99designs/gqlgen/graphql/handler"
"your-project/graph/generated"
"your-project/graph"
)
func GraphqlHandler() gin.HandlerFunc {
srv := handler.NewDefaultServer(
generated.NewExecutableSchema(
generated.Config{Resolvers: &graph.Resolver{}},
),
)
return func(c *gin.Context) {
srv.ServeHTTP(c.Writer, c.Request)
}
}
- 路径必须匹配:比如注册在
POST /graphql,前端就要发到/graphql,不是/query或/api/graphql - 别漏掉
router.POST("/graphql", GraphqlHandler())—— Gin 不会自动扫描函数名 - 如果同时要 GraphiQL 页面,额外加一条
GET /graphql路由,返回playground.Handler(需单独 import)
resolver 函数 panic: “no such method” 怎么查?
这不是编译错误,是运行时反射调用失败。gqlgen 在生成的 generated.go 里硬编码了方法名、参数类型、返回值顺序,哪怕只差一个 * 或大小写,都会崩。
检查三件事:
- 函数名是否严格匹配 schema 字段名:
users≠Users≠getUsers - 第一个参数必须是
ctx context.Context,不能省略或换位置 - 返回值类型必须和
models_gen.go里生成的 struct 完全一致:[]*model.User不能写成[]model.User或map[string]interface{}
例如 schema 定义 users(first: Int): [User!]!,对应 resolver 签名必须是:
func (r *queryResolver) Users(ctx context.Context, first *int) ([]*model.User, error)
schema 改了但 resolver 没更新,怎么避免?
gqlgen generate 不监听文件变化,改完 schema.graphqls 必须手动再跑一次。否则 generated.go 还是旧接口,新字段根本不会出现在 resolver 接口里,你写了也没人调用。
- 开发时建议加个 Makefile 或 alias:
alias gqlg='go run github.com/99designs/gqlgen generate' - CI 流程里强制加一步:
gqlgen generate && git diff --exit-code graph/generated/,防止遗漏提交 - 新增
input类型或Mutation时,注意gqlgen.yml的models段是否已映射对应 Go 结构体,否则生成器跳过整个链路
为什么返回 nil 却不是 GraphQL 的 null?
Go 基本类型(int, string)和非指针结构体无法表示 null。schema 里写 name: String!,生成的是 *string;但如果写成 name: String(可空),生成的是 *string,你返回 nil 才真为 null。
- 字段带
!(非空),返回值类型必须是非指针或非 nil 指针,否则 panic - 字段不带
!(可空),返回值类型必须是指针(*string,*int),才能返回nil表示 null - 切片同理:
[User!]→[]*model.User,空切片[]是有效值,不是 null;要表示“无数据”,得返回nil
最容易被忽略的是:resolver 返回零值(如 0, "")会被 GraphQL 当作真实数据下发,前端收不到 null,调试时误以为“后端没查到”,其实是类型定义和实现没对齐。


















