为什么 GraphQL 难以流行?设计不足还是设计过度?

发布: (2025年12月13日 GMT+8 22:58)
5 min read
原文: Dev.to

Source: Dev.to

I. 简化 GraphQL 服务开发

如果让 Zhipu Qingyan AI 使用 getBookById 函数编写一个 GraphQL 示例,它会生成如下代码:

@Configuration
public class GraphQLConfig {

    @Bean
    public GraphQLSchema graphQLSchema() {
        String schema = "type Book { id: ID!, title: String, author: String }" +
                        "type Query { getBookById(id: ID!): Book }";
        SchemaParser schemaParser = new SchemaParser();
        TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);

        RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
                .type("Query", builder ->
                   builder.dataFetcher("getBookById", environment -> {
                    String bookId = environment.getArgument("id");
                    // Add logic to fetch the book here; this is just an example
                    return Book.builder().id(bookId)
                        .title("Sample Book Name").author("Sample Author").build();
                }))
                .build();

        SchemaGenerator schemaGenerator = new SchemaGenerator();
        return schemaGenerator.makeExecutableSchema(
                  typeDefinitionRegistry, runtimeWiring);
    }
}

这看起来相当复杂。graphql-java 库引入了模式解析、类型定义注册以及运行时 wiring 等概念。服务函数必须写成 DataFetcher,并通过 DataFetchingEnvironment 获取前端参数。然而,这种写法暴露了 GraphQL 引擎的底层实现,显得有些过时。

在最新的 Spring GraphQL 框架中,只需要几个简单的注解——框架会自动处理这些复杂性:

@Controller
public class BookController {

    @QueryMapping
    public Book getBookById(@Argument Long id) {
        // ...
    }
}

有了这种封装,业务代码只需要少量注解和 POJO;通常不需要使用内部的 graphql-java 接口。框架会自动分析 Java 类定义并生成 GraphQL 类型定义,省去了手动维护 schema 的步骤。

Quarkus 框架同样提供了成熟的 GraphQL 支持,并且在 Spring 之前就引入了类似的注解机制:

@ApplicationScoped
@GraphQLApi
public class BookService {

    @Query("getBookById")
    public Book getBookById(@Name("id") Long id) {
        return ...
    }
}

Nop 平台的 NopGraphQL 框架也使用注解来标记服务函数:

@BizModel("Book")
public class BookBizModel{
   @BizQuery
   public Book getBookById(@Name("id") Long id){
     ...
   }
}

在基本的 GraphQL 服务支持之上,NopGraphQL 通过 CrudBizModel 与 NopORM 数据访问引擎深度集成,提供对常见 CRUD 操作(包括复杂的分页查询、子表过滤以及主从更新)的完整支持,通常无需额外代码。

详细介绍请参见文章《Nop 平台与 APIJSON 的功能对比》。

GraphQL 的设计比传统 Web 框架更纯粹;它不引入绑定于 Web 运行时环境的概念(如 Request 与 Response),因此很容易实现完全基于 POJO 的封装。不过,GraphQL 返回的是固定的 JSON 格式,无法直接实现文件上传/下载功能。NopGraphQL 为此新增了 /f/upload 扩展,使其语义更加完整。

观看 B 站视频:《Nop 平台如何为 GraphQL 增加文件上传/下载支持》。

II. 为 GraphQL 扩展返回状态码

GraphQL 协议的整体设计相当完整,尤其提供了大量内置的可扩展特性。Nop 平台利用 GraphQLResponse 中的 extensions map 来存放额外的返回状态码:

@DataBean
public class GraphQLResponseBean {
    List errors;
    Object data;
    Map extensions;

    @JsonIgnore
    public String getErrorCode() {
        return (String) getExtension("nop-error-code");
    }

    @JsonIgnore
    public int getStatus() {
        if (extensions == null)
            return 0;
        int defaultStatus = hasError() ? -1 : 0;
        return ConvertHelper.toPrimitiveInt(
            extensions.get("nop-status"),
            defaultStatus,
            NopException::new);
    }
}

借助 GraphQL 指令作为扩展机制,NopGraphQL 框架还引入了更多面向业务的特性,以简化典型的应用服务。详情请参见《Nop 入门:如何创意性地扩展 GraphQL》。

III. GraphQL 与 REST 的等价性

表面上,GraphQL 提供了许多超越传统 REST 服务的高级特性。有趣的是,严格的理论分析表明,GraphQL 在数学上等价于在普通 REST 服务上额外加入一个用于选择返回字段的特殊 @selection 参数。Nop 平台建立了以下等价关系,使同一后端服务函数既可以通过 GraphQL 也可以通过 REST 访问。

query{
  Book__get(id: 123) { name, title }
}

等价于

/r/Book__get?id=123&@selection=name,title

从这个视角看,GraphQL 只是一种 pull‑mode 的 REST 调用。在 Nop 平台的实现中……(内容未完)

Back to Blog

相关文章

阅读更多 »

前6种 API 架构风格

以下是六大 API 架构风格及其推荐使用场景:1️⃣ SOAP(Simple Object Access Protocol):SOAP 适用于企业级…