Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >REST 已死:为什么你的 .NET API 应该迁移到 GraphQL

REST 已死:为什么你的 .NET API 应该迁移到 GraphQL

作者头像
郑子铭
发布于 2025-04-13 10:46:25
发布于 2025-04-13 10:46:25
8700
代码可运行
举报
运行总次数:0
代码可运行

你是否在犹豫是否要在 .NET 应用中从 REST 转向 GraphQL。我在两种技术领域都有多年经验,在此分享所有心得体会——包括优点、缺点和挑战。


我们将涵盖以下内容

  • • GraphQL 的真正定义(通俗易懂)
  • • 在 .NET 项目中设置 GraphQL(逐步指南)
  • • 与 REST 的真实对比(含代码)
  • • 何时使用(以及何时不用)GraphQL
  • • 真正重要的性能考量
  • • 不影响生产环境的迁移策略

GraphQL 究竟是什么?

基础理解

GraphQL 是一种 API 查询语言,允许客户端按需获取数据。与 REST(服务器决定每个端点返回的数据)不同,GraphQL 让客户端精确指定所需数据。

就像在餐厅点餐——与其接受固定菜单(REST),不如按需定制你的订单(GraphQL)。

类型系统

GraphQL 的核心是强类型系统。每个 GraphQL 服务都定义了一组类型,完整描述可查询的数据。

定义 GraphQL API 时,需先定义这些类型:

  • 对象类型:主数据模型(如 UserOrderProduct
  • 标量类型:基础数据类型(StringIntBoolean 等)
  • 输入类型:用于变更操作的参数类型
  • 枚举:允许的值集合
  • 接口:其他类型可实现的抽象类型

定义类型后,GraphQL 会自动强制执行。你无法请求不存在的字段,且总能获得预期的结果。


操作类型

GraphQL 有三种主要操作类型:

  1. 1. 查询(Queries):获取数据(类似 REST 的 GET)
    • • 单次查询可请求多个资源
    • • 字段可无限嵌套
    • • 始终保持幂等性(不改变数据)
  2. 2. 变更(Mutations):修改数据(类似 REST 的 POST/PUT/DELETE)
    • • 单次请求可执行多个修改
    • • 返回更新后的数据
    • • 顺序执行(不同于查询)
  3. 3. 订阅(Subscriptions):实时更新
    • • 与服务器保持活动连接
    • • 数据变更时接收更新
    • • 适用于聊天应用、实时动态等

REST 与 GraphQL 对比

REST 方式(需多个端点)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GET /api/users/
GET /api/users//orders
GET /api/users//preferences

需发起三次独立请求,且无论是否需要都会获取所有字段。响应示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 第一次请求:/api/users/123
{
    "id":,
    "name":"John Doe",
    "email":"john@example.com",
    "phoneNumber":"555-0123",
    "address":"123 Main St",
    "registerDate":"2024-01-01",
    "lastLoginDate":"2024-03-15"
}

// 第二次请求:/api/users/123/orders
{
    "orders":[
        {
            "id":,
            "date":"2024-03-01",
            "total":99.99,
            "items":[...],
            "shippingAddress":"...",
            "billingAddress":"...",
            "status":"delivered"
        }
    ]
}

// 第三次请求:/api/users/123/preferences
{
    "preferences":{
        "theme":"dark",
        "emailNotifications":true,
        "language":"en",
        "timezone":"UTC-5"
    }
}
GraphQL 方式(单次请求,按需获取)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
query {
    user(id: ) {
        name
        email
        orders {
            total
            date
        }
        preferences {
            theme
        }
    }
}

响应仅包含请求的字段:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "data":{
        "user":{
            "name":"John Doe",
            "email":"john@example.com",
            "orders":[
                {
                    "total":99.99,
                    "date":"2024-03-01"
                }
            ],
            "preferences":{
                "theme":"dark"
            }
        }
    }
}

GraphQL 执行流程

当查询到达时,GraphQL 会:

  1. 1. 解析查询以理解请求的字段
  2. 2. 将每个字段匹配到对应的解析器(Resolver)
  3. 3. 尽可能并行执行解析器
  4. 4. 将结果组装成请求的精确结构

解析器是 GraphQL 执行的核心。它们是负责获取模式中每个字段数据的函数。你可以将其视为“微型端点”,每个端点负责一个特定的数据片段。

这与 REST 有本质区别——在 REST 中,每个端点通常映射到单个控制器操作;而在 GraphQL 中,可能需要数十个解析器协同工作以满足单个查询。


性能考量

我在一个中型应用(约 130 万条记录)上进行了测试,结果如下:

0️⃣ 简单单资源请求

  • • REST:45ms
  • • GraphQL:48ms(简单请求略有开销)

1️⃣ 包含关联数据的复杂请求

  • • REST(多端点):320ms
  • • GraphQL(单次请求):89ms(GraphQL 优势明显!)

2️⃣ 用户配置文件的网络负载

  • • REST:24KB(完整用户对象)
  • • GraphQL:8KB(仅请求的字段)

何时不应使用 GraphQL?

实话实说——它并非万能:

  1. 1. 简单 CRUD 应用 如果只是构建基础管理面板,REST 可能更简单。
  2. 2. 文件上传 GraphQL 虽支持,但比 REST 复杂。
  3. 3. 小团队且工期紧张 学习曲线可能对小型项目不划算。

在 .NET 中设置 GraphQL(逐步指南)

0️⃣ 生态

HotChocolate 是 .NET 中最流行的 GraphQL 服务器,优势包括:

  • • 专为 .NET 构建
  • • 高性能
  • • 丰富功能集
  • • 活跃社区
  • • 定期更新

其他选项如 GraphQL.NET 也存在,但 HotChocolate 因与 ASP.NET Core 的深度集成成为事实标准。

1️⃣ 安装包
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dotnet add package HotChocolate.AspNetCore
dotnet add package HotChocolate.Data
  • HotChocolate.AspNetCore: 提供 ASP.NET Core 集成、HTTP 处理、GraphQL 执行管理和模式配置。
  • HotChocolate.Data: 支持过滤、排序、分页和 Entity Framework Core 集成。
2️⃣ 领域模型设计
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public classUser
{
    publicint Id { get; set; }
    publicstring Name { get; set; }
    publicstring Email { get; set; }
    public List<Order> Orders { get; set; }
}

publicclassOrder
{
    publicint Id { get; set; }
    publicdecimal Total { get; set; }
    public DateTime OrderDate { get; set; }
    publicint UserId { get; set; }
    public User User { get; set; }
}
3️⃣ 创建 GraphQL 类型

注解驱动方式(最简单)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public classQuery
{
    publicasync Task<User?> GetUser([Service] IUserRepository repository, int id)
    {
        returnawait repository.GetUserByIdAsync(id);
    }

    publicasync Task<IEnumerable<User>> GetUsers([Service] IUserRepository repository)
    {
        returnawait repository.GetUsersAsync();
    }
}

类型优先方式(更灵活)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UserType : ObjectType<User>
{
    protected override void Configure(IObjectTypeDescriptor<User> descriptor)
    {
        descriptor.Field(f => f.Id).Type<NonNullType<IdType>>();
        descriptor.Field(f => f.Name).Type<NonNullType<StringType>>();
        descriptor.Field(f => f.Email).Type<NonNullType<StringType>>();
        
        descriptor
            .Field(f => f.Orders)
            .ResolveWith<UserResolvers>(r => r.GetOrders(default!, default!))
            .UseDbContext<AppDbContext>();
    }
}

高级 GraphQL 实践

4️⃣ 添加过滤、排序和分页
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Query
{
    [UsePaging(MaxPageSize = 50)]
    [UseProjection]
    [UseFiltering]
    [UseSorting]
    public IQueryable<User> GetUsers([Service] IUserRepository repository)
    {
        return repository.GetUsers();
    }
}

查询示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
query {
    users(
        where:{
            name:{contains:"John"}
            AND:{
                orders:{some:{total:{gt:}}}
            }
        }
        order:[
            {name: ASC }
            {email: DESC }
        ]
        first:
        after:"YXJyYXljb25uZWN0aW9uOjk="
    ){
        edges {
            node {
                name
                email
                orders {
                    total
                    orderDate
                }
            }
            cursor
        }
        pageInfo {
            hasNextPage
            endCursor
        }
    }
}

N+1 查询问题及解决方案

问题示例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public classUserType : ObjectType<User>
{
    protected override void Configure(IObjectTypeDescriptor<User> descriptor)
    {
        descriptor
            .Field(f => f.Orders)
            .Resolve(async context =>
            {
                var user = context.Parent<User>();
                // 🚫 每个用户触发独立查询!
                returnawait _orderRepository.GetOrdersForUserAsync(user.Id);
            });
    }
}
解决方案:DataLoader 模式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public classOrdersByUserDataLoader : BatchDataLoader<int, List<Order>>
{
    privatereadonly IOrderRepository _orderRepository;

    public OrdersByUserDataLoader(
        IOrderRepository orderRepository,
        IBatchScheduler batchScheduler)
        : base(batchScheduler)
    {
        _orderRepository = orderRepository;
    }

    protectedoverrideasync Task<IReadOnlyDictionary<int, List<Order>>> LoadBatchAsync(
        IReadOnlyList<int> userIds,
        CancellationToken cancellationToken)
    {
        // 单次查询获取所有用户的订单
        var allOrders = await _orderRepository.GetOrdersByUserIdsAsync(userIds);
        
        // 按用户 ID 分组返回
        return allOrders
            .GroupBy(o => o.UserId)
            .ToDictionary(g => g.Key, g => g.ToList());
    }
}

注册 DataLoader

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddGraphQLServer()
        .AddQueryType<Query>()
        .AddDataLoader<OrdersByUserDataLoader>()
        .AddProjections()
        .AddFiltering()
        .AddSorting();
}

本文基于在 .NET 企业应用中实施 GraphQL 的真实经验,所有代码示例均经过测试并可直接用于生产环境。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# 一分钟浅谈:GraphQL 与 REST 比较
随着互联网技术的快速发展,API 设计模式也在不断进化。REST 和 GraphQL 是两种非常流行的 API 设计风格。本文将从概念、优缺点以及如何在 C# 中实现这两个 API 风格进行比较,并通过代码案例进行解释。
Jimaks
2024/12/09
2770
C# 一分钟浅谈:GraphQL 数据类型与查询
随着Web开发技术的不断进步,GraphQL作为一种数据查询和操作语言,逐渐成为现代Web应用中的重要组成部分。相比传统的REST API,GraphQL提供了更加灵活和高效的数据获取方式。本文将从C#的角度出发,简要介绍GraphQL的基本概念、数据类型以及查询方法,并通过具体的代码示例来帮助读者更好地理解和使用GraphQL。
Jimaks
2024/12/01
1940
造轮子之集成GraphQL
先简单对比以下GraphQL和WebAPI: GraphQL和Web API(如RESTful API)是用于构建和提供Web服务的不同技术。
饭勺oO
2023/10/18
3090
造轮子之集成GraphQL
【.NET 遇上 GraphQL】使用 Hot Chocolate 构建 GraphQL 服务
Hot Chocolate 是 .NET 平台下的一个开源组件库, 您可以使用它创建 GraphQL 服务, 它消除了构建成熟的 GraphQL 服务的复杂性, Hot Chocolate 可以连接任何服务或数据源,并创建一个有凝聚力的服务,为您的消费者提供统一的 API。
全球技术精选
2022/01/04
7660
【.NET 遇上 GraphQL】使用 Hot Chocolate 构建 GraphQL 服务
GraphQL:现代API设计的革新
GraphQL是由Facebook在2012年开发并于2015年开源的一种查询语言,用于构建API。与传统的REST API相比,GraphQL提供了一种更高效、更灵活的数据查询方式。本文将从GraphQL的基本概念、核心特性、实际使用以及优缺点等方面进行详细介绍。
IT蜗壳-Tango
2024/06/23
2350
GraphQL 初体验,Node.js 构建 GraphQL API 指南
过去几年中,GraphQL 已经成为一种非常流行的 API 规范,该规范专注于使客户端(无论是客户端、前端还是第三方)的数据获取更加容易。
coder_koala
2021/01/08
8.5K1
REST API和GraphQL API的比较
REST(表述性状态传输)API 是一种应用程序接口 (API) 的架构风格,它使用 HTTP 请求来访问和使用数据。该数据可用于GET、PUT、POST和DELETE数据类型,指的是对资源的读取、更新、创建和删除操作。 RESTful API 使用 HTTP 方法在处理数据时执行 CRUD(创建、读取、更新和删除)过程。 为了促进缓存、AB 测试、身份验证和其他过程,标头向客户端和服务器提供信息。 主体包含客户端想要传输到服务器的数据,例如请求的有效负载。
用户4235284
2023/10/14
7650
REST API和GraphQL API的比较
Repository Pattern已死?深入剖析.NET中的设计模式争议与最佳实践
在.NET生态中,鲜有话题能像 仓储模式(Repository Pattern) 这般引发激烈争论。有些开发者奉其为整洁架构的基石,另一些人则认为它是被Entity Framework Core(EF Core)淘汰的冗余设计。
郑子铭
2025/05/17
750
Repository Pattern已死?深入剖析.NET中的设计模式争议与最佳实践
GraphQL与传统API对比介绍教程
在现代应用程序开发中,API(应用程序接口)扮演着至关重要的角色。随着技术的发展,API的实现方式也在不断进化。本文将介绍两种常见的API实现方式:传统API(主要是REST)和GraphQL,并对它们进行对比分析。
IT蜗壳-Tango
2024/06/22
3070
C#一分钟浅谈:GraphQL 中的数据加载
随着Web技术的发展,GraphQL作为一种数据查询和操作语言,逐渐成为现代Web应用中不可或缺的一部分。它提供了更高效、灵活的数据获取方式,相比传统的REST API,能够显著减少网络请求次数和数据传输量。本文将从C#的角度出发,探讨GraphQL中的数据加载机制,包括常见的问题、易错点以及如何避免这些问题。
Jimaks
2024/12/11
1580
C# 一分钟浅谈:GraphQL 优化与性能提升
GraphQL 是一种用于 API 的查询语言,它提供了一种更有效和强大的方式来获取数据。与传统的 REST API 不同,GraphQL 允许客户端精确地请求所需的数据,从而减少了不必要的数据传输。然而,随着 GraphQL 应用的复杂性增加,性能问题也逐渐显现。本文将从常见的性能问题入手,逐步探讨如何优化 GraphQL API。
Jimaks
2024/12/08
1940
使用 GraphQL 进行 API 设计:从入门到实战
作为一名开发者,我一直对 API 设计充满兴趣。最初,我主要使用 RESTful API,但随着前端需求的日益复杂,REST 的一些局限性逐渐显现,比如数据过载(获取的字段太多)和数据不足(一次请求拿不到所需的数据)。后来,我接触了 GraphQL,它的灵活性和高效性让我眼前一亮。
Echo_Wish
2025/02/28
2930
使用 GraphQL 进行 API 设计:从入门到实战
为什么我使用 GraphQL 而放弃 REST API?
本文最初发布于 Max Desiatov 的个人博客,经原作者授权由 InfoQ 中文站翻译并分享。
winty
2021/05/19
2.5K0
安息吧 REST API,GraphQL 长存
即使与 REST API 打交道这么多年,当我第一次了解到 GraphQL 和它试图解决的问题时,我还是禁不住把本文的标题发在了 Twitter 上。
疯狂的技术宅
2019/03/27
2.8K0
安息吧 REST API,GraphQL 长存
GraphQL 与 ASP.NET Core 集成:从入门到精通
随着Web应用的发展,传统的RESTful API已经无法满足现代应用的需求。GraphQL作为一种查询语言,允许客户端请求所需的数据,并且能够减少不必要的数据传输,提高API的灵活性和性能。本文将详细介绍如何在ASP.NET Core中集成GraphQL,包括常见问题、易错点以及如何避免这些问题。
Jimaks
2024/12/04
1590
C# 一分钟浅谈:GraphQL 客户端调用
随着互联网应用的发展,API 的设计模式也在不断进化。从传统的 RESTful API 到现代的 GraphQL API,后者以其灵活性和高效性逐渐受到开发者的青睐。本文将简要介绍如何在 C# 中调用 GraphQL API,并探讨一些常见的问题、易错点及如何避免这些问题。
Jimaks
2024/11/30
1890
在 Laravel 应用中构建 GraphQL API
昨天我们学习了 在 Visual Code 中搭建 Laravel 环境,现在我们来学习 Facebook 的 GraphQL 。
猿哥
2019/07/24
3.7K0
使用ASP.NET Core开发GraphQL服务器 -- 预备知识(上)
为了介绍使用ASP.NET Core构建GraphQL服务器,本文需要介绍一下GraphQL,其实看官网的文档就行。
solenovex
2018/10/10
1.8K0
C# 一分钟浅谈:GraphQL 安全性考虑
随着 GraphQL 在 Web 开发中的广泛应用,其安全性问题也逐渐成为开发者关注的焦点。GraphQL 是一种用于 API 的查询语言,它提供了更高效的数据获取方式,但也带来了新的安全挑战。本文将从常见的安全问题出发,探讨如何在 C# 中实现安全的 GraphQL API。
Jimaks
2024/12/10
1660
REST API 和 GraphQL的比较
REST(Representational State Transfer)和GraphQL是两种常见的API设计风格,各自有其独特的特点和适用场景。在API设计方面,REST和GraphQL各有其优势和劣势。
coderidea
2024/02/01
3250
REST API 和 GraphQL的比较
推荐阅读
相关推荐
C# 一分钟浅谈:GraphQL 与 REST 比较
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验