2.1 资源建模:契约的主体


2.1 资源建模:契约的主体

本节摘要:资源建模决定契约到底在管什么。本节教你识别业务领域里哪些概念够格当资源(通常指"能命名的名词"),把它们组织成对象、集合、子资源三类,并处理"动作"与"预支付账单"这类资源化困难户。资源建模直接决定后续 URI 长什么样、该用哪个方法,是四根构件的起点。

学习目标

阅读完本节,你应当能够:

  1. 判断一个概念是否适合作为资源,并区分对象、集合、子资源三类。
  2. 把一个订单-订单项-客户的领域切开成规范化资源。
  3. 把"发送邮件""确认入库"这类动作,分别用动作资源或过程状态化解。
  4. 解释为什么"先建模、后定 URI"能避免后期返工。

为什么建模要走在写 URI 之前

做过接口的人大概都见过这种返工:先把 URL 一个个写出来,写到一半发现"我要的是语义,不是字节",于是开头写的 /getUsers/deleteUser 全推倒重来。前半段天真,后半段方法论。

资源建模存在的意义,是把"造什么接口"这个业务问题先于"怎么拼 URI"这个技术问题解决掉。业务没想清楚,URI 写得再漂亮也是沙上建塔;反之建模建清楚了,URI 几乎是被推出来的,不用费力想。

二、识别资源:谁够格当"名词"

REST 的核心信条是"把世界拆成能命名的名词"。识别资源可以走一套快速筛查:

  • 是不是一个对象:用户、订单、商品——指代单个实体的名词,天然是资源。
  • 是不是一组对象的集合:用户列表、订单列表——集合资源,通常对应 GET /usersGET /orders
  • 是不是嵌套在某个对象下的关系:某个用户的订单——子资源,对应 GET /users/123/orders

一个概念如果无法稳定命名、或者只是"一顿操作"而非"一个东西",往往不适合直接当资源。拿三个典型例子对照:

概念 是否资源 处理方式
一个用户 是,对象 资源 users 下的实例
用户列表 是,集合 资源 users 本身
发送确认邮件 不是,动作 建"通知任务"资源或走过程状态

先把领域资源切割归纳成一张图,再顺着单元逐个展开:

02-01-fig01

图:电商领域资源切割示意

三、解剖一个真实领域

拿电商订单域做一次完整切开。业务里有:用户能下单,订单包含若干订单项,订单有收货地址、有支付、有发货状态。

先识别资源,再画关系:

  • 用户 users
  • 订单 orders(子资源:一个订单下的订单项 order-items、支付记录 payments)
  • 商品 products

关系上,用户在 /users/123他下单的订单列表在 /users/123/orders订单 456 的明细在 /orders/456/items。注意一种取舍:订单是挂在用户下面还是独立成顶层?独立成顶层更常见——因为订单的业务生命周期与用户相对独立,且 GET /orders/456 不依赖你在哪个用户会话里。

{ "id": 456, "status": "paid", "userRef": "/users/123", "items": [ {"productRef": "/products/7", "qty": 2} ] }

上面的订单表示里,userRefproductRef 用完整 URI 指代关联资源,而不是塞一个裸的数值 id。这样客户端拿到表示,就能知道去哪 follow 关联——这是"通过表示操作"与后续 HATEOAS 的伏笔。

判断"挂子资源还是独立底层"还有一条经验:子资源只在"没有它父对象就没意义"时成立。订单项离开订单确实没意义,所以天然是 /orders/456/items;而商品、用户离开订单仍独立存在,所以留在顶层。先把实体间"依赖还是并立"的关系辨清,建模就不会为了"看起来整齐"而强行嵌套出一堆没必要的层级。

四、动作类需求的两种解法

业务里总有被动词附身的时刻:sendEmailactivateUsercheckoutCart。硬要把它们塞成资源会拿到怪异的 URI。两种常规解法:

  • 过程状态资源化:把"一次操作"建模成"一个有状态的任务"。"确认入库"可以建模成 POST /orders/456/confirmations 创建一条确认记录,或 POST /orders/456/actions/confirm 明确表达"在订单 456 上执行确认动作"。前者偏资源,后者偏动作资源,工程上都常见。
  • 动作资源:确实必要且不能复用标准方法时,给动作本身一个资源。但这是例外不是默认,滥用会把资源体系瓦解回 RPC。

⚠️ 常见坑:逢操作就造 POST /sendEmailPOST /approveLeave 一排动词端点。短期顺手,长期侵蚀资源体系的统一性。先尝试用"创建一条状态记录"来表达动作。

五、建模与后序构件的咬合

建模决策会一路传导到后面:你决定订单独立成顶层资源,URI 就少了 users/123/orders 这层深度;你决定支付是订单子资源,GET /orders/456/payments 就有了归属;你决定确认走动作资源,方法语义就要在 POST 与 201 上多做文章。所以本节是四根构件的"最先输入",返工成本也最高——建模错了,后面三节全跟着错。

💡 关键直觉:一个好模型应让客户端"不看文档也能猜到 URI"。资源的名字越贴合业务直觉,接口的自解释性越强,越经得起长期演进而不需要频繁改。

本节要点回顾

  • 要点一:资源建模优先于 URI 设计,先定义"管什么"再谈"怎么写"。
  • 要点二:对象、集合、子资源是三种基本资源形态,识别靠问"是不是能命名的名词"。
  • 要点三:订单类生命周期独立的实体优先做成顶层资源。
  • 要点四:动作类需求用"过程状态资源"或"动作资源"化解,避免动词 URI 泛滥。
  • 要点五:资源间用 URI 引用而非裸 id,为表示操作与 HATEOAS 留口子。
  • 要点六:建模决策会传导到 URI、方法与状态码,是返工成本最高的构件。

主体定盘,下一节就给这份主体登记一张规范的地籍图——URI 设计的每一笔都有讲究。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U