gpt4 book ai didi

ruby-on-rails - 版本 Rails 3 API 的正确方法

转载 作者:行者123 更新时间:2023-12-04 02:09:39 25 4
gpt4 key购买 nike

我有一个 Rails 3 引擎,它公开了大约 20 个 Controller 的 API 路由。这些 Controller 代表不同嵌套级别的几种不同资源,并被 500 多个 rspec 测试覆盖。 API 在 v1 版本中使用命名空间和基于版本 header 的路由约束,默认为 v1。这是许多博客文章中描述的版本控制系统,似乎是最佳实践。

这些博客文章都没有描述您如何实际管理推出新版本。我必须对单个 Controller 的输出进行重大更改。此更改通过更改其中一个 JSON 值的结构来影响对象的 JSON 响应。这将导致该 Controller 的索引、显示和编辑 View 中断。

很明显,我可以复制所有 app/api/v1app/api/v2 [1]。然后我可以对我的新 v2 序列化程序进行一次更改。我现在有大量重复的代码,用于 API 的第 2 版,几乎没有做任何更改。我需要在两个地方维护代码。我可能必须让我的整个 rspec 套件在版本 2 Controller 以及版本 1 Controller 上运行,并对 v2 序列化程序进行一点额外测试。这听起来像是一个可怕的想法。对于从 v1 Controller 继承的 v1 命名空间中的每个未更改的 Controller ,我们可以有一些 stub v2 Controller 。这听起来也不是很好。

我能想到的最佳选择是在我的 v2 API 中使用一个 Controller (在这种情况下可能只是一个序列化程序),并使用一些路由魔术来检查所需版本的 Controller 是否存在并回退到以前的版本直到找到一个。序列化器版本也应该有类似的魔法来检查这个版本是否存在并回退直到找到一个。这引入了最少的额外代码,并且不会立即使我的测试套件的持续时间加倍。它需要能够将一个函数直接插入到 rails 路由逻辑中,然后才能为我丢失的 v2 Controller 返回 404。可能我可以基于文件系统分析所有 Controller 的命名空间,并在 Rails 启动时生成带有回退的路由,但是很难管理从 API 的先前版本中显式删除路由。

似乎我们需要继续为每个非附加功能/输出格式更改执行此操作,直到每个以前的版本都被弃用和删除。我们还有一个未发布的 API,其中包含约 75 个 Controller ,涵盖约 4000 个规范。当我们开始在外部记录和发布这些内容时会发生什么?

除了以我们发布功能的速度进行不可行的 API 更改批处理之外,其他人如何管理这个?上面的想法可能吗?有没有更好的办法?

[1] 问题一。我们正在使用 ActiveModel::Serializers用于生成 JSON 响应。 ActiveModel::序列化器 doesn't support API versioning ,虽然似乎有一个 way around this使用 ruby 魔法来选择正确的类(class)。

最佳答案

项目 ActiveModel::Serializers 的编号为 issues与版本控制有关,one of them提供了如何通过命名空间模块实现版本控制的想法,但它在 2 天前关闭,随后是开发人员的话:

As you noticed we have discussed versioning on other issues and PR's as well, and I'm glad to read so really nice thought from all of you.



所以 AMS 版本控制的问题确实存在但尚未解决。

回到原来的问题:

It's obvious that I can copy all of app/api/v1 to app/api/v2. I can then make my single change to my new v2 serializer. I've now got a large amount of duplicated code for a version 2 of an API that has made almost no changes. I need to maintain code in two places.



继承复杂性与副作用 VS 代码重复之间存在折衷。如果有经过良好测试的 V1 代码库,应锁定以进行任何修改, 维护确实意味着在运行回归测试套件时没有错误 .版本 1 开发周期结束,测试编写完毕,契约(Contract)行为签署。代码重复 V1-V2 是有意义的,它避免了回归失败。

I'll probably have to have my whole rspec suite run on the version 2 controllers as well as the version 1 ones with a tiny bit of extra testing for the v2 serializer. This sounds like a horrible idea.



我不同意这是一个可怕的想法,这是预期行为和想象中的开发便利之间的权衡。避免规范套件被复制也不容易。 Controller 、模型可以重复使用,但规范代码库更有可能被复制,以 100% 确信新更改不会破坏以前的 API 版本。

The best option that I can think of is to have a single controller (in this case probably just a single serializer) inside my v2 API, with some routing magic to check if a controller for the required version exists and to fall back through previous versions until it finds one.



是的,这听起来不错,有助于避免应用程序代码(虽然不是规范套件)重复,但需要额外的开发工作和维护。您尝试执行的操作称为写时复制,仅复制更改。这是众所周知的优化技术。尽管如此,HTTP 回退听起来更合适。

Possibly I could analyse the namespaces for all controllers based on the filesystem and generate routes at rails boot time with fallbacks but it would be difficult to manage explicitly removing routes from a previous version of the API.



假设您有超过 2 个版本的 API,并且某个 API 调用有 2 个后备祖先,其中第二个被开发人员的错误破坏,您会拦截不仅 404 还拦截 500 异常吗?如果最新的 DB 方案版本破坏了向后兼容性怎么办?

We have an additional unreleased API consisting of ~75 controllers covered by ~4000 specs. What happens when we start externally documenting and releasing these?



这更像是架构问题,而不是具体的实现。如果 API 往往很大,API 设计模式可以帮助避免构建难以支持和维护的单体 API。

我会建议做什么:
  • 将 V1 完全复制到 V2,包括 rspec 套件
  • 不要害怕在运行测试上花费 2 倍的时间
  • 等到 AMS 发布版本控制(版本 v0.10.x)
  • 将单体 API 拆分为基于
  • 的单个 API

    如果代码重复 Not Acceptable ,另一种选择是复制 Rails 应用程序并部署到同一服务器并使用 Nginx 配置分派(dispatch)请求:
    location /v1 {
    proxy_pass http://http://unix:/tmp/v1_backend.socket:/v1/;
    }

    location /v2 {
    proxy_pass http://http://unix:/tmp/v2_backend.socket:/v2/;
    }

    此特定代码仅作为示例显示,我并不是说每个版本都有 10 个不同的 Rails 应用程序是一个好主意。

    回到最初的问题,API 版本控制很困难,对于某些 API 客户端来说,拥有默认(最新)API URL 端点是有意义的。

    关于ruby-on-rails - 版本 Rails 3 API 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30852006/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com