使用 Go 和 gqlgen 实现 GraphQL API:实战指南

embedded/2025/1/31 6:01:04/

使用 Go 和 gqlgen 实现 GraphQL API:实战指南

在本文中,我将分享如何使用 Go 语言和 gqlgen 框架实现一个完整的 GraphQL API。我们将构建一个包含用户、文章和评论功能的博客系统 API。

技术栈

  • Go
  • gqlgen (GraphQL 框架)
  • MySQL (数据存储)
  • Redis (缓存,可选)

项目结构

go_graphql/
├── config/
│   └── database.go     # 数据库配置
├── graph/
│   ├── model/          # 数据模型
│   ├── schema.graphqls # GraphQL schema
│   └── schema.resolvers.go # Resolver 实现
├── server.go           # 主程序入口
└── gqlgen.yml         # gqlgen 配置文件

GraphQL Schema 设计

首先,我们需要定义 GraphQL schema,这是整个 API 的基础:

graphql">type User {id: ID!username: String!email: String!avatar: StringcreatedAt: String!posts: [Post!]comments: [Comment!]
}type Post {id: ID!title: String!content: String!author: User!category: Category!createdAt: String!updatedAt: Stringcomments: [Comment!]images: [Image!]
}type Comment {id: ID!content: String!author: User!post: Post!createdAt: String!
}type Query {users: [User!]!user(id: ID!): Userposts(categoryId: ID): [Post!]!post(id: ID!): Post
}type Mutation {createUser(input: CreateUserInput!): User!createPost(input: CreatePostInput!): Post!createComment(input: CreateCommentInput!): Comment!
}

Resolver 实现

下面是一个完整的用户查询 resolver 实现示例:

// Users resolver 实现
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {rows, err := config.DB.Query(`SELECT id, username, email, avatar, created_at FROM users`)if err != nil {return nil, fmt.Errorf("failed to query users: %v", err)}defer rows.Close()var users []*model.Userfor rows.Next() {var user model.Uservar createdAt time.Timeerr := rows.Scan(&user.ID, &user.Username, &user.Email, &user.Avatar, &createdAt)if err != nil {return nil, fmt.Errorf("failed to scan user: %v", err)}user.CreatedAt = createdAt.Format(time.RFC3339)users = append(users, &user)}return users, nil
}// User 类型的 posts 字段 resolver
func (r *userResolver) Posts(ctx context.Context, obj *model.User) ([]*model.Post, error) {rows, err := config.DB.Query(`SELECT p.id, p.title, p.content, p.created_at, p.updated_at, p.category_id, p.author_id FROM posts p WHERE p.author_id = ?`, obj.ID)if err != nil {return nil, fmt.Errorf("failed to query posts: %v", err)}defer rows.Close()var posts []*model.Postfor rows.Next() {var post model.Postvar createdAt, updatedAt time.Timevar categoryID, authorID stringerr := rows.Scan(&post.ID, &post.Title, &post.Content, &createdAt, &updatedAt, &categoryID, &authorID)if err != nil {return nil, fmt.Errorf("failed to scan post: %v", err)}post.CreatedAt = createdAt.Format(time.RFC3339)updatedAtStr := updatedAt.Format(time.RFC3339)post.UpdatedAt = &updatedAtStrposts = append(posts, &post)}return posts, nil
}

代码生成

gqlgen 是一个强大的 GraphQL 代码生成工具,它可以:

  1. 根据 schema 自动生成 Go 类型
  2. 生成所有必要的接口和类型定义
  3. 保持自定义实现代码不变

使用以下命令生成代码:

go run github.com/99designs/gqlgen generate

生成的代码包括:

  • graph/generated/generated.go: 包含所有生成的接口和类型
  • graph/model/models_gen.go: 包含根据 schema 生成的 Go 结构体
  • graph/schema.resolvers.go: 包含 resolver 实现的框架代码

最佳实践

  1. 类型安全:利用 Go 的类型系统和 gqlgen 的代码生成确保类型安全

  2. 错误处理

    if err != nil {return nil, fmt.Errorf("failed to query users: %v", err)
    }
    
  3. 资源清理:使用 defer 确保资源正确释放

    defer rows.Close()
    
  4. 时间处理:统一使用 RFC3339 格式处理时间

    createdAt.Format(time.RFC3339)
    
  5. 空值处理:对可选字段使用指针类型

    updatedAtStr := updatedAt.Format(time.RFC3339)
    post.UpdatedAt = &updatedAtStr
    

http://www.ppmy.cn/embedded/157965.html

相关文章

实时数据处理与模型推理:利用 Spring AI 实现对数据的推理与分析

在现代企业中,实时数据处理与快速决策已经成为关键需求。通过集成 Spring AI,我们不仅可以高效地获取实时数据,还可以将这些数据输入到 AI 模型中进行推理与分析,以便生成实时的业务洞察。 本文将讲解如何通过 Spring AI 实现实时…

使用github提交Pull Request的完整流程

文章目录 1.Fork仓库2. git clone 仓库在本地3.对项目进行修改开发4.上传项目到远程仓库操作补充1. git add .2. git commit -m "提交信息"3. git pull4. git push总结完整工作流程示例 5.将更新的项目pull Request给原来的仓库主人 当多人进行项目的开发的时候&…

怎么样把pdf转成图片模式(不能复制文字)

贵但好用的wps, 转换——转为图片型pdf —————————————————————————————————————————— 转换前: 转换后: 肉眼可见,模糊了,且不能复制。 其他免费办法,参考&…

算法-移除元素

hello 大家好!今天开写一个新章节,每一天一道算法题。让我们一起来学习算法思维吧! /*** 原地移除数组 nums 中所有值等于 val 的元素,并返回剩余元素的数量* param {number[]} nums - 输入的数组* param {number} val - 要移除…

Qt Ribbon使用实例

采用SARibbon创建简单的ribbon界面 实例代码如下所示&#xff1a; 1、头文件&#xff1a; #pragma once #include <SARibbonBar.h> #include "SARibbonMainWindow.h" class QTextEdit; class SAProjectDemo1 : public SARibbonMainWindow { Q_OBJECT pub…

Docker Desktop 解决从开发到部署的高效容器化工作流问题

一、基本概念 Docker Docker 是一个开源的容器化平台&#xff0c;提供了一种轻量级的方式来打包、运行和管理应用程序及其依赖项。通过 Docker&#xff0c;你可以&#xff1a; 容器化应用程序&#xff1a;将代码、依赖项和配置打包成一个独立的容器镜像。便携性&#xff1a;…

Spring MVC 综合案例

目录 一. 加法计算器 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 3. 服务器端代码 4. 运行测试 二. 用户登录 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 (1) 登录界面接口 (2) 首页接口 3. 服务器端代码 4. 运行测试 三. 留言板 1. 准备…

使用 C/C++ 调用 libcurl 调试消息

在使用 C/C 调用 libcurl 进行 HTTP 请求时&#xff0c;有时我们需要查看请求的/应答消息的内容&#xff08;包括请求头和请求体&#xff09;以方便调试。libcurl 提供了多种方法来捕获和输出这些信息&#xff0c;本文介绍具体的使用方式。 1. libcurl 调试工具简介 libcurl 是…