遵循Restful规范的简单的栗子
- 前端代码:
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" />
</head>
<body>
<div id="app">
<div style="display: flex;flex-direction: column;">
<el-input v-model="form.name" autocomplete="off" placeholder="姓名" style=""></el-input>
<el-button v-on:click="get">GET</el-button>
<el-button v-on:click="post">POST</el-button>
<el-button v-on:click="del">DELETE</el-button>
<el-button v-on:click="put">PUT</el-button>
<el-button v-on:click="logs=[]">Clear Log</el-button>
</div>
<!-- 日志部分 -->
<ul>
<li v-for="(log, idx) in logs" :key="idx">
{{log}}
</li>
</ul>
</div>
<script>
axios.defaults.baseURL = "http://localhost:3000";
axios.interceptors.response.use(
response => {
app.logs.push(JSON.stringify(response.data));
return response;
},
err => {
app.logs.push(JSON.stringify(response.data));
return Promise.reject(err);
}
)
var app = new Vue({
el: '#app',
data: {
form: {
name: 'marron',
id: 3
},
logs: []
},
methods: {
async post() {
const res = await axios.post("/users", this.form);
},
async get() {
const res = await axios.get("/users");
},
async put() {
const res = await axios.put("/users", this.form);
},
async del() {
const res = await axios.delete("/users/3");
}
}
})
</script>
</body>
</html>
- 后端代码
const Koa = require("koa");
const app = new Koa();
const Router = require("koa-router");
const router = new Router({ prefix: "/users" });
const cors = require("koa2-cors");
const bodyParser = require("koa-bodyparser");
app.use(cors());
app.use(bodyParser());
const users = [{id:1 , name:"tom"}, {id:2, name: "jerry"}];
// 查找数据 ?name = xx
router.get("/", ctx =>{
console.log("GET /users");
const {name} = ctx.query; // ?name = xx
let data = users;
if (name) {
data = users.filter (u => u.name === name);
}
ctx.body = {ok: 1, data};
});
// 查找数据 /users/1 id = 1
router.get("/:id", ctx =>{
console.log("GET /users/:id");
const {id} = ctx.params; // /users/1
const data = users.find(u => u.id == id);
ctx.body = {ok:1 , data};
});
// 新增用户
router.post("/", ctx=>{
console.log("POST /users");
const {body: user} = ctx.request; // 请求body
user.id = users.length +1;
users.push(user);
ctx.body = { ok: 1};
});
router.put("/", ctx => {
console.log("PUT /users");
const {body: user} = ctx.request; // 请求body
const idx = users.findIndex(u => u.id == user.id);
if(idx > -1){
users[idx] = user;
}
ctx.body = { ok: 1};
});
// 删除用户 /users/1 删除id为1
router.delete("/:id", ctx =>{
console.log("DELETE /users/:id");
const {id} = ctx.params;
const idx = users.findIndex(u => u.id === id);
if( idx > -1){
users.splice(idx, 1);
}
ctx.body ={ ok: 1};
});
app.use(router.routes());
app.listen(3000, ()=>{
console.log("[Server] Server is running at http://localhost:3000");
})
Restful规范几个注意:
- 动宾结构
客户端发出的指令都是"动词 + 宾语"的结构,如: “GET / articles” - 动词的覆盖
可以使用 X-HTTP-Method-Override属性告诉服务器使用哪一个动词覆盖POST方法
POST /api/marron/1 HTTP/1.1
X-HTTP-Method-Override: PUT
上面指明了PUT方法.
在服务器端(koa2)使用下面方法接受
router.put("/api/marron:id", async ctx=>{
})
- 宾语必须是名词,且尽量为复数
不要出现/getnames
或/name
之类的,尽量使用/names
- 尽量扁平化
不要出现GET /authors/12/categories/2
,如果可以,尽量使用GET /authors/12?categories=2