关于 restful api 想必不用多说,已经有很多文章都阐述过它的设计原则,但遵循这个原则可以让你的 API 接口更加规范吗?以下是我对 restful api 风格的一些思考🤔。
思考
此时不妨思考一个问题,现在以下几个接口,你会怎么去设计 url 路径?
- 查询文章
- 查看文章详情
- 创建文章
- 更新文章
- 删除文章
- 查看我的文章
- 查看他人的文章
前 5 个接口想必不难设计,这边就给出标准答案。
- 查询文章
GET /articles
- 查看某篇文章详情
GET /articles/:id
- 创建文章
POST /articles/
- 更新文章
PUT /articles/:id
- 删除文章
DELETE /articles/:id
当然,我相信肯定也有GET /article—list
POST /add-article
这样的答案,不过这些不在 restful api 风格的范畴,就不考虑了。
而这时 查看我的文章 或许就需要稍加思考,或许你会有以下几种方式
GET /my-articles
从资源角度来看肯定不好,因为此时在 url 不能很直观地体现请求资源,同时在控制器文件(controller) 就与 article 分离了,并且还占用了 / 下路径。GET /articles/mine
则又不那么遵循 restful api 风格,挺违和的。
那么这时不妨遵循 资源从属关 系,在这里 文章所属的对象就用户,因此查看他人的文章可以这么设计GET /users/:userId/articles
获取特定用户(userId)的文章列表。
而 查看我的文章 同样也可用此 URL,只需将 userId 更改为自己的便可。从 api 的 URL 来看是很舒服了,但是从代码开发的角度上问题又有了问题了。。。
对于 user 资源,是不是也有查询,创建,更新,删除等接口,即 查询用户 GET /users
,创建用户POST /users/
等等。。
我是不是就需要在 user 这么重要的资源控制器上去添加一些其他方法,所对应的代码就如下所示
@Controller('users')
export class UserController {
constructor(private userService: UserService, private articleService: ArticleService) {}
@Get()
async list(@Query() dto: UserQueryDto) {
return this.userService.findAll(dto)
}
@Get(':id')
async info(@Param('id') id: number) {
return this.userService.findOne(id)
}
@Post()
async create(@Body() dto: UserCreateDto) {
await this.userService.create(dto)
}
// 省略有关 User 部分接口,以下是其他 user 下的资源接口
@Get(':userId/articles')
async articles(@Param('userId') userId: number) {
return this.userService.findAll(userId, articlesId)
}
@Get(':userId/articles/:articlesId')
async articles(@Param('userId') userId: number, @Param('articlesId') articlesId: number) {
return this.articleService.find(userId, articlesId)
}
}