2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

为什么说要用 DDD 替代 CRUD 来设计 API

  • 2017-09-18
  • 本文字数:2187 字

    阅读完需:约 7 分钟

来自亚马逊的高级工程师 James Hood 以简单明了的例子说明了为什么要用 DDD 替代 CRUD 来设计 REST API。

REST 以资源为中心,这些资源以 URI 的形式呈现。在调用 HTTP 时,通过指定一个 HTTP 动词和一个资源 URI 对某个特定的资源进行操作。大部分 REST 框架都提供了生成器,你只要指定一个资源的名字,框架就会为你生成脚手架(scaffold)。不过,这些生成器默认使用的是 CRUD 模型(Create、Read、Update、Delete),它们把资源看成是一系列属性的集合,使用 JSON 或与特定语言相关的数据对象来表示资源,并生成用于对资源进行创建、读取、更新和删除操作的方法。

虽然这给开发者带来了便利,但我觉得这样是有问题的。我不喜欢 CRUD 这样的说法,尤其不喜欢当中的 U。一般的更新操作允许客户端更新资源的任何一个字段,并使用新版本覆盖已有的版本。但如果你允许客户端这么做,那么你的服务 API 就失去了应有的价值。服务层的一个关键价值在于为底层的数据增加业务约束,因此,资源最终都需要带上业务约束。

那么,难道我们就不能给更新操作增加业务约束吗?让我们以最简单的银行账户为例。首先,不能让客户通过调用 API 来随意更新他们的账户余额。另外,账户或许需要最小余额的限制。你在更新操作里做了一些检查,账户余额的变动必须发生在一个指定的范围内。那么这样问题就解决了吗?当然没有。任何一次余额的调整都需要与某种事务相对应,不是吗?是存入、取出,还是转账?如果客户要更改账户该怎么办?这样做是被允许的吗?这样做会不会破坏与其他数据之间的关系?不难看出,你的更新操作很快会让这一切变得像意大利面条一样混乱不堪。我曾经看着一些团队走上了这条不归路,他们试图从更新的字段里去推测客户的意图,结果代码变得像团乱麻。

那么该如何解决这个问题,有其他更好的方案吗?我个人更喜欢基于领域驱动设计(DDD)来设计 API。DDD 的基本思想是说,软件的建模应该发生在真实世界的问题得到解决之后。DDD 使用实体(Entity)和聚合(Aggregate)来描述业务对象,还定义了服务(Service)、值对象(Value Object)和仓库(Repository)等术语,用以解决业务领域或 DDD 边界上下文问题。DDD 不一定非要与 REST 绑定在一起,不过我发现 DDD 与 REST API 近乎天然地合拍,因为 REST 的资源可以很好地与 DDD 的实体映射起来。

那么这意味着什么呢?这意味着,你的 API 应该要以领域对象以及这些对象所提供的业务操作为中心。业务操作是对常规更新操作最好的替代品。我们继续以之前的银行账户为例。

对于银行的 API 来说,账户就是一个领域对象(DDD 里的实体)。这次我们不再使用 CRUD 来为账户建模,而是为账户定义一组业务操作。以下是一系列写入操作:

  • 开户(Open)——新开一个账户。
  • 销户(Close)——注销一个已有的账户。
  • 取出(Debit)——从账户里扣掉一些钱。
  • 存入(Credit)——往账户里存入一些钱。

这些操作都带有一定的业务约束。例如,往一个已经注销的账户里存钱是不被允许的,而在取钱的时候要强制检查最小余额。至于读取操作,我们可以为客户提供一些有用的查询。

  • 加载(Load)——通过账户 ID 加载相应的账户信息。
  • 交易历史——列出账户的交易历史。
  • 客户的账户列表——列出指定客户的所有账户。

在定义好业务操作之后,就可以将它们与 REST API 映射起来。

  1. POST /account ——新开一个账户。
  2. PUT /account/ /close ——注销一个已有的账户。
  3. PUT /account/ /debit ——从账户里扣掉一些钱。
  4. PUT /account/ /credit ——往账户里存入一些钱。
  5. GET /account/ ——通过账户 ID 加载相应的账户信息。
  6. GET /account/ /transactions ——列出账户的交易历史。
  7. GET /accounts/query/customerId/ ——列出指定客户的所有账户。

这些看起来与一般的 CRUD API 非常的不一样,关键在于这些操作具有良好的定义。不管对于服务提供方还是客户端来说,这样的体验都更好。服务提供方不再需要根据更新字段来推测业务操作的意图,业务操作清晰明了,这样的代码更简单,也更容易维护。而对于客户端来说,它们能执行或不能执行哪些操作也是一目了然的。如果 API 具有良好的文档化,比如使用了 Swagger ,那么就可以很清楚地了解到 API 都具有哪些约束。

定义这样的 API 需要做一些前期思考,这不同于使用简单的 CRUD 生成器。如果你打算将 API 暴露成公共端点,就需要在很长的一段时间内为 API 提供支持,最好还是把它看成是一个永久性的事项。我总是建议人们在前期多花一点时间,因为有些东西到了后面就很难修改,而 API 就是一个很好的例子。

所以,在进行 API(REST 或其他)设计时,请停止使用 CRUD 模型。相反,可以通过 DDD 来定义 API,包括领域对象和它们的业务操作。

如果你想看到更多关于领域对象的例子,可以参考 Amazon Web Services 的 API。在 AWS API 开发者指南里,每一个服务都有对应的“关键概念”一节,用以描述领域对象。例如,S3 里定义了 Bucket、Object 和 Permission 等领域对象,Kinesis 里定义了流(stream)和分片(shard)。先了解一个服务的领域对象,再查看 API 参考,然后浏览服务的 API 清单。你会发现,基于这些领域对象构建的 API 在理解和使用上都更加直观。

查看英文原文: There is No U in CRUD


感谢雨多田光对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-09-18 16:596372
用户头像

发布了 322 篇内容, 共 150.4 次阅读, 收获喜欢 148 次。

关注

评论

发布
暂无评论
发现更多内容

Flink CDC 3.4 发布, 优化高频 DDL 处理,支持 Batch 模式,新增 Iceberg 支持

Apache Flink

大数据 flink Flink CDC

反而是一个一个的客户教会了我如何接单

程序员郭顺发

HarmonyOS5云服务技术分享--匿名登录功能指南

莓创技术

使用 LangChain + Higress + Elasticsearch 构建 RAG 应用

阿里巴巴云原生

阿里云 云原生 Higress

HarmonyOS5云服务技术分享--ArkTS开发Node环境

莓创技术

HarmonyOS5云服务技术分享--自有账号对接AGC认证

莓创技术

HarmonyOS5云服务技术分享--ArkTS开发函数

莓创技术

用户反馈如何帮助企业实现降本增效?

Feedalyze

效率工具 产品经理 用户体验 产品运营 用户反馈

详解鸿蒙仓颉开发语言中的日志打印问题

幽蓝计划

MRP都搞不好,何谈生产管理过关!

积木链小链

数字化转型 智能制造 生产管理

Solana 上的Vibe Coding(氛围式编程)正崛起

PowerVerse

AI web3 DePIN

快来认领你的开源任务!开源之夏 - 可观测项目发布!

阿里巴巴云原生

阿里云 云原生 可观测

AI极客低代码平台快速上手--创建应用

华哥的全栈次元舱

Java Python vuetify 纯血鸿蒙 AIGC低代码平台

JManus - 面向 Java 开发者的开源通用智能体

阿里巴巴云原生

spring 阿里云 云原生

从运维告警到业务决策:可观测性正在重新定义企业数据基础设施

观测云

可观测性

火山引擎发布豆包·语音播客模型,秒级生成“真人对话”播客

新消费日报

HarmonyOS5云服务技术分享--登录邮件功能整理

莓创技术

HarmonyOS5云服务技术分享--云函数创建配置指南

莓创技术

游戏盾功能与技术解析

网络安全服务

游戏开发 服务器 手游 DDoS 攻击 游戏盾

HarmonyOS5云服务技术分享--退出登录文档问题

莓创技术

信创堡垒机助力政企IT系统实现IT运维国产化

行云管家

数字化 信创 堡垒机

乘云数字荣获“鑫智奖·2025专家推荐TOP10优秀解决方案”奖项

乘云数字DataBuff

数字化转型 故障定位 金融数字化 业务监控

数据湖和数据仓库的区别

镜舟科技

数据仓库 数据湖 数据存储 大数据分析 湖仓一体

HarmonyOS5云服务技术分享--账号登录文章整理

莓创技术

AI 极客低代码平台快速上手 -- 设计领域类

华哥的全栈次元舱

Java Python vuetify 纯血鸿蒙 AIGC低代码平台

HarmonyOS5云服务技术分享--手机号登录教程

莓创技术

HarmonyOS5云服务技术分享--账号关联开发指南

莓创技术

高敏感数据行业怎么定义?需要用到堡垒机吗?

行云管家

网络安全 堡垒机 高敏感数据

Sentieon文献解读-使用 Sentieon ctDNA 分析管道高精度、高效地处理 UMI 数据集

INSVAST

umi 肿瘤测序 Sentieon 基因变异检测 生信分析服务

AskTable 集成 Databend:结构化数据的 AI 查询新体验

Databend

NFT 的叙事正在改变:看懂 NFT 的进化路径

NFT Research

NFT NFT\ web3、

为什么说要用DDD替代CRUD来设计API_语言 & 开发_James Hood_InfoQ精选文章