You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD/整洁架构下REST服务Task类双JSON序列化方法的设计与测试咨询

关于DDD/整洁架构下Task类序列化的问题

先明确你的场景:你定义了一个领域类Task,现在需要两种JSON序列化逻辑:

  • 一种用于MongoDB的持久化,输出原始路径格式的JSON
  • 另一种用于REST API响应,输出拼接了服务地址的完整URL格式的JSON
@attr.s
class Task:
    id: str = attr.ib()
    url: str = attr.ib()
    images_paths: Optional[List[str]] = attr.ib(default=None)
    text_path: Optional[str] = attr.ib(default=None)

下面针对你的三个疑问逐一解答:

1. 这两种序列化方法是否应放在基础设施层?从DDD视角来看是否合理?

完全不应该把这两个序列化逻辑放在Task领域类里,按照DDD和整洁架构的原则,领域层应该保持绝对纯净,只包含核心业务逻辑,不依赖任何外部技术细节(比如持久化、API格式)。

正确的做法是:

  • 用于MongoDB的序列化:属于持久化细节,应该放在基础设施层(比如和MongoDB仓库实现类放在一起,或者单独的MongoDB序列化工具类)。这部分是领域对象和数据库存储格式之间的转换,属于外部依赖的适配。
  • 用于REST API的序列化:属于API适配层的逻辑,应该放在接口适配器层(比如API控制器所在的模块,或者专门的DTO转换类)。这部分是领域对象到API响应格式的转换,服务于对外暴露的接口协议。

这样设计的好处是:领域层不依赖任何外部系统,当你更换数据库(比如从MongoDB换成PostgreSQL)或者修改API响应格式时,完全不需要改动Task类本身,符合依赖倒置原则。

2. 二者均为JSON序列化方法,该如何命名?

命名的核心是明确上下文和用途,避免模糊的通用名称,推荐这些命名方式:

  • MongoDB序列化:serialize_to_mongo_document、to_mongo_json、as_mongo_dict——直接体现是给MongoDB存储用的
  • REST API序列化:serialize_to_api_response、to_api_dto、as_api_response_dict——明确是用于API输出的DTO转换

举个例子,基础设施层里的MongoDB序列化方法可以这样写:

def serialize_task_to_mongo(task: Task) -> dict:
    return attr.asdict(task)

API层的序列化方法:

def serialize_task_to_api(task: Task, base_url: str) -> dict:
    task_dict = attr.asdict(task)
    if task_dict["images_paths"]:
        task_dict["images_paths"] = [
            f"{base_url}/tasks/{task.id}/images/{os.path.basename(path)}"
            for path in task_dict["images_paths"]
        ]
    if task_dict["text_path"]:
        task_dict["text_path"] = f"{base_url}/tasks/{task.id}/text/{os.path.basename(task_dict['text_path'])}"
    return task_dict

3. 常规序列化测试无法用于REST API序列化场景,该如何进行测试?

REST API的序列化是单向转换(从领域对象到API响应,一般不需要从API响应反序列化回领域对象,因为API输入会用专门的请求DTO),所以不能用双向相等断言,而是要针对输出内容做针对性测试:

测试思路:

  1. 构造一个已知状态的Task实例
  2. 调用API序列化方法,得到响应字典
  3. 逐一断言响应字典中的每个字段是否符合预期格式和值

示例测试代码(用pytest):

def test_serialize_task_to_api():
    test_task = Task(
        id="1",
        url="aaa.com",
        images_paths=["img.png"],
        text_path="text.txt"
    )
    base_url = "localhost"
    api_response = serialize_task_to_api(test_task, base_url)
    
    # 断言核心字段一致
    assert api_response["id"] == test_task.id
    assert api_response["url"] == test_task.url
    
    # 断言路径被正确拼接
    assert api_response["images_paths"] == ["localhost/tasks/1/images/img.png"]
    assert api_response["text_path"] == "localhost/tasks/1/text/text.txt"
    
    # 可选:测试空值场景
    empty_task = Task(id="2", url="bbb.com")
    empty_response = serialize_task_to_api(empty_task, base_url)
    assert empty_response["images_paths"] is None
    assert empty_response["text_path"] is None

如果你的API有明确的JSON Schema,还可以用jsonschema库验证响应是否符合Schema定义,确保格式的一致性。

内容的提问来源于stack exchange,提问作者Mateusz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:38:46