「清洁 API 架构」六部曲·Part 1:分层全景 + Ruby 实战,告别“Fat Controller”!

作者:API传播员 · 2025-11-08 · 阅读时间:6分钟

我们开始了一个关于如何构建 Web API 的六部分系列,旨在介绍多年来各种语言和框架提出或使用的多种架构模式。其中,Clean 架构是线上讨论最为广泛的架构之一。它通过将项目划分为多个层次来实现关注点分离,每一层都遵循单一职责原则。这种设计不仅让每个类专注于处理流程的一部分,还能更轻松地进行单元测试。

Clean 架构适用于多个领域。在另一个博客系列中,我们曾探讨如何将 Clean 架构应用于移动应用程序。而今天,我们将重点讨论如何将 Clean 架构应用于 API 端点,这种方法被我们称为 清洁 API 架构

💡 想让指标可衡量、团队节奏更透明?「开发任务管理系统 KPI」提示词可帮你基于 AI 超级提示词,快速制定与业务成果对齐的 KPI,兼顾用户参与度与业务成果!


一、清洁 API 架构的层次划分 🏗️

层级 职责 Ruby 示例对象
Frameworks & Drivers 路由、HTTP、DB、外部服务 Rails Controller、Sidekiq Job
Interface Adapters 类型化 Request、Presenter、Socket Relay Request 类、JSONPresenter
Application Logic 编排、权限、事务边界 ServiceCommand
Entity Logic 领域模型、业务规则 RepositoryAdapterEntity

🛠️ 写完 Service 别忘了跑「代码优化」提示词,一键诊断慢查询与重复请求,让接口响应提速 30 %!


二、控制器(Controller)—— 编排而非业务 🎛️

1. 只做三件事

  1. 提取并验证 HTTP 参数 → Request 对象
  2. 身份认证 & 授权
  3. 调用 Application Service,返回 Result

2. 依赖清单

  • Validator → 语法校验
  • Presenter → 输出格式化
  • Socket Relay → WebSocket 推送
  • Request → 类型化参数封装
# app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
  def create
    request = CreateFavoriteRequest.new(params)
    result  = AddToFavoriteService.call(request, current_user)
    present(result) # JSONPresenter
  end
end

三、Application Logic —— 用例层 💼

① 读流程(GET)

  • Service → 校验语义、权限 → Repo/Adapter 取数据 → 返回 Result

② 写流程(POST/PUT/DELETE)

  • Service → 校验 → 写入 DB → 推送副作用(Job、WebSocket)
# app/services/add_to_favorite_service.rb
class AddToFavoriteService
  include Dry::Monads[:result]

  def self.call(request, user)
    return Failure(:invalid_target) unless request.valid?
    favorite = FavoriteRepo.first_or_create(user.id, request.target_id)
    Success(favorite)
  end
end

四、Entity Logic —— 可复用的基础设施 🔌

组件 说明 示例
Repository 聚合根持久化 FavoriteRepo
Adapter 外部 API 访问 S3AdapterElastiCacheAdapter
Entity 领域对象/聚合根 Favorite

📖 想给同事一份秒懂的接口文档?「代码文档生成器」可自动生成标准化字段描述、请求/响应示例与错误码,让协作零阻力!


五、双重验证机制 ✅

  1. 语法验证 —— Request 层(类型、必填、格式)
  2. 语义验证 —— Service 层(业务规则、权限、状态)
class CreateFavoriteRequest
  include ActiveModel::Model
  attr_accessor :target_id, :creator_id
  validates :target_id, presence: true, numericality: true
end

六、测试策略 🧪

  • 单元测试 → Service、Repository 用内存 SQLite
  • 集成测试 → Controller 用 instance_double Mock 外部适配器
  • 契约测试 → 确保 Request/Response JSON Schema 不变
RSpec.describe AddToFavoriteService do
  it "creates favorite when valid" do
    result = described_class.call(valid_request, user)
    expect(result).to be_success
  end
end

七、Ruby 代码分层全景图 🗺️

# Frameworks & Drivers 层
post '/favorite' do
  request = CreateFavoriteRequest.new(params)
  result  = AddToFavoriteService.call(request, current_user)
  present(result)
end

# Application 层
class AddToFavoriteService
  def self.call(request, user)
    return Failure(:invalid) unless request.valid?
    favorite = FavoriteRepo.first_or_create(user.id, request.target_id)
    Success(favorite)
  end
end

# Entity 层
module FavoriteRepo
  def self.first_or_create(user_id, target_id)
    Favorite.where(user_id: user_id, target_id: target_id).first_or_create!
  end
end

八、常见疑问 ❓

Q1. 层太多会不会过度工程?
→ 单体 MVP 可先保持 3 层(Controller-Service-Repo),用户量>10w 再细化。

Q2. 性能会不会下降?
→ 层间调用都是内存对象,无网络开销;瓶颈多在 DB 和外部 API。

Q3. 必须 Ruby 吗?
→ 分层思想语言无关;Python/FastAPI、Java/Spring Boot、Go 均可映射。


九、结语 🎯

清洁 API 架构带来的好处:

  • ✅ 关注点分离 —— 易定位 bug、易单元测试
  • ✅ 可扩展 —— 新增用例只需加 Service/Repository
  • ✅ 可维护 —— 每层单一职责,新人一周上手

先用「代码生成」快速产出 Service 模板与 Repository 接口,再用 KPI 面板持续监控每层耗时、测试覆盖率与线上错误率,你的 API 将更快、更稳地迎接高并发挑战!🚀

原文链接: https://medium.com/perry-street-software-engineering/clean-api-architecture-2b57074084d5