Rails REST API 的某个请求 URL 非常长,大家怎么看?

davidwei · 2015年07月01日 · 最后由 msg7086 回复于 2015年07月06日 · 4986 次阅读

REST 把数据视为资源,通过 URI 对资源进行唯一的标识。

一般是这样的:http://example*com/customers/1234

或者是这样的:http://example*com/orders/2007/10/776654

在具体项目中,如果某个 API 关联很深,就可能会导致 URI 会很长,举个不恰当的例子:中国有很多 University ;

关系如下:

University has_many colleges
  College has_many clazzs
    Clazz has_many students
      Student has_many elective_courses
        ElectiveCourse has_many homeworks
          Homework has_many scores

如果我要获取 XX 大学 XX 学院 XX 学生 XX 课程 XX 作业的成绩中第 N 次成绩,URI 好像是这样的:

/universities/:univerity_id/colleges/:college_id/clazzs/:clazz_id/students/:student_id/elective_coruses/:elective_course_id/homeworks/:homework_id/scores/:score_id

如果在逻辑中会判断所有参数的有效性(比如 university 是否存在,某个 college_id 是否在某个 univerty 存在...) , 这种情况在复杂逻辑关联中会出现。

虽然不是处女座,但是看到这么长的 URI 好纠结。话说稍旧的 Swagger 也会让这个 URI 不换行。

不知道各位在实践中是如何处理类似问题的,希望提出意见。谢谢。

Option 1:

/scores/:score_id?univerty_id=1&college_id=2&clazz_id=3&student_id=4& ... &homework_id=10

2.7.1 Limits to Nesting http://guides.rubyonrails.org/routing.html#limits-to-nesting

Resources should never be nested more than 1 level deep.

和 reset 没关系啊,你自己生成的 url...

如果 score_id 是全局唯一的话

GET /scores/:id

就可以了啊。在生成这个 url 的时候,就把该检查学校学生检查好了。

这里面主要的问题是:什么是 REST。

#4 楼 @emanon URL 嵌套很多,导致很长很长。在 Swagger 调试时不好找,而且感觉怪怪的。

#3 楼 @ch3n 嗯。不过这些相当于反向冒泡去获取所有的关联。如果层数很多,也会查询很多次。

#2 楼 @hooopo 嗯。是的,没有关系。但是所有的参数我会校验是否属于某个父对象,一层一层,好纠结。

直接/scores/:score_id 就好了。

我从另一个角度给你解释为什么不需要带上上层的 id:

假设你给另外系统提供 API 接口,获取 score 信息,正常情况是 /scores/:score_id,对方有 score id 就可以 CRUD 了。而你要是把嵌套信息也加到 url 里,那么对方请求你一次 API 需要知道你整个数据库的结构了,才能给你提供 univerty_id college_id clazz_id student_id homework_id,这就是耦合。因为你自己的页面一般查完 score 就查 college 等信息你没发觉而已。

如果 URL 中是 slug 还有点意义,纯 ID 的话 😪

可是试着组织特定 ID 格式,如:1-2-3-4 找到 score 验证其他 ID.

提示:

如果需要这么严格的验证的话,最好在 score 中把 univerty_id, college_id, clazz_id, student_id, homework_id 都放在表里,一级级向上/下关联很耗资源。

建议善用主键。 主键总是唯一的,直接单层就好了。 嵌套资源本意是用作语义优化,但是你带上这么长的 url,根本就优化不了语义了。 article/1/comment/2 这种能直接看出 comment 与 article 的依赖关系,一个评论是基于一篇文章的。 但是 university/2/college/25/clazz/843/student/8928305/score/2333855 这种 url,score 跟 university 跟 college 都完全没有关系的,根本没必要放在一个 url 里了。

你这种情况,最多最多,/student/:id/score/:id 就足够了。

首先谢谢各位的热心回答。 @hooopo @msg7086 如果要检查从属关系呢,比如 a 是 A 学校 B 学院 C 班级的学生,在提交的时候他把自己的 student_id 改成 b 学生的 id。有什么比较 OK 的方式来预防这种情况呢?thx

#11 楼 @davidwei 什么?学生可以改自己的成绩?没有权限控制?亲你别吓我……

#12 楼 @msg7086 我举例可能不太恰当,如果老师提交成绩的话。。

#13 楼 @davidwei 老师提交成绩的时候改 student_id 做什么? 而且就算改了又有什么问题? 提交成绩属于 create 又不是 update。 能不能写入数据要根据权限来定。 跟 url 什么关系?

检查权限可以先查询到要修改的对象,然后向上查关联对象直到用来判断的那一层,不一定要按 url 顺序。

楼主要么不知道怎么设计这张数据库表,要么不理解当前的表为什么这么设计。

#16 楼 @TheWaWaR 不是简单的对某个资源做处理,还要检查数据的操作者是否修改的是自己的资源

#17 楼 @davidwei 大概理解你的意思了

1、老师 F 属于 大学 A -> 学院 B -> 班级 C 2、学生 G 也属于大学 A -> 学院 B -> 班级 C

你的问题:老师 F 能否修改 学生 G 的成绩?

也不需要通过你那么长的 url 完成判断 1、老师和学生添加关联关系 或 2、老师和学生是否在同一班级(任课/学习)确认

你没有交待清楚班级(或上级)、老师、学生之间的关系 如果考虑到老师跨院系甚至跨学校任教的情况,仅利用那大长串 URL 来判断,不知道你遇到过麻烦的地方没有 这可能是没有必要的(具体还得根据你的业务需求定)

有 id 的话没必要嵌套,嵌这么多层其实是不如直接用文件系统存的... url 太长也是有问题的... 各浏览器支持的最长 url 不一样...

#17 楼 @davidwei 总之我们可以总结出一句话:你 uri 里就算只包含了最后一个 id,也可以通过代码重建出前面的那一大串 id。 那么前面那串 id 就是冗余数据,完全没用。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号