# RESTful 风格的 API

RESTful 是一种风格,在RESTful中,一切都被认为是资源,每个资源有对应的URL标识.

不是标准也不是协议,只是一种风格。当然你也可以不按照他的风格去写。

# URL 路径

# 传统接口
POST    http://localhost:3000/api/user/add
GET     http://localhost:3000/api/user/delete?id=1
POST    http://localhost:3000/api/user/update
GET     http://localhost:3000/api/user/get?id=1
GET     http://localhost:3000/api/user/get_list?page=5&size=10
#  RESTful
POST    http://localhost:3000/api/user
PATCH   http://localhost:3000/api/user/1
DELETE  http://localhost:3000/api/user/1
GET     http://localhost:3000/api/user/1
GET     http://localhost:3000/api/user?page=5&size=10

# Version 版本控制

版本控制一共有三种,我们一般用第一种,更加语义化

METHOD DESC
URI Versioning 版本将在请求的 URI 中传递(默认)
Header Versioning 自定义请求标头将指定版本
Media Type Versioning 请求的Accept标头将指定版本

开启版本控制,这里我们使用 URI 版本控制的方式

import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('api'); // 全局路由前缀
  app.enableVersioning({ // 版本控制
    type: VersioningType.URI,
  })
  await app.listen(3000);
  console.log('http://localhost:3000');
}
bootstrap();

在 Controller 中定义版本

import { Controller, Get, Post, Body, Patch, Param, Delete, Version } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
 
@Controller({
  path: 'user',
  version: '1',
})
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
  }

  @Delete(':id')
  delete(@Param('id') id: string) {
    return this.userService.delete(id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.userService.update(id, updateUserDto);
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.userService.findOne(id);
  }

  @Get()
  findAll(@Param('page') page: number, @Param('size') pageSize: number) {
    return this.userService.findAll(page, pageSize);
  }
}

# 测试

#  RESTful
POST    http://localhost:3000/api/v1/user
DELETE  http://localhost:3000/api/v1/user/1
PATCH   http://localhost:3000/api/v1/user/1
GET     http://localhost:3000/api/v1/user/1
GET     http://localhost:3000/api/v1/user?page=5&size=10
GET /api/v1/user/1 HTTP/1.1
HTTP/1.1 304 Not Modified
X-Powered-By: Express
ETag: W/"35-R1cVG6L9A0n7zHYh5ZgyqGdx2/4"
Date: Tue, 18 Apr 2023 17:19:21 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"id":1,"accountName":"default","nickName":"default"}
GET /api/v1/user/2 HTTP/1.1
HTTP/1.1 403 Forbidden
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 46
ETag: W/"2e-Qr1syB64EvQy4xRh4mjhujkK1ck"
Date: Tue, 18 Apr 2023 17:19:50 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"statusCode":403,"message":"用户不存在"}