本文转自:
REST API规范
编写REST API,实际上就是编写处理HTTP请求的async函数,不过,REST请求和普通的HTTP请求有几个特殊的地方:REST请求仍然是标准的HTTP请求,但是,除了GET请求外,POST、PUT等请求的body是JSON数据格式,请求的Content-Type为application/json;
REST响应返回的结果是JSON数据格式,因此,响应的Content-Type也是application/json。1、工程结构2、目录详解
package.json:项目描叙{
"name": "rest-koa", "version": "1.0.0", "description": "rest-koa project", "main": "app.js", "scripts": { "dev": "node --use_strict app.js" }, "keywords": [ "koa", "rest", "api" ], "author": "david pan", "dependencies": { "koa": "2.0.0", "koa-bodyparser": "3.2.0", "koa-router": "7.0.0" }}app.jsconst Koa = require('koa');const app = new Koa();const bodyParser = require('koa-bodyparser');const controller = require('./controller');const rest = require('./rest');// parse request body:app.use(bodyParser());// bind .rest() for ctx:app.use(rest.restify());// add controller:app.use(controller());app.listen(3000);console.log('app started at port 3000...');(1). controller.js--- 路由集中处理
const fs = require('fs');
// add url-route in /controllers:function addMapping(router, mapping) { for (var url in mapping) { if (url.startsWith('GET ')) { var path = url.substring(4); router.get(path, mapping[url]); console.log(`register URL mapping: GET ${path}`); } else if (url.startsWith('POST ')) { var path = url.substring(5); router.post(path, mapping[url]); console.log(`register URL mapping: POST ${path}`); } else if (url.startsWith('PUT ')) { var path = url.substring(4); router.put(path, mapping[url]); console.log(`register URL mapping: PUT ${path}`); } else if (url.startsWith('DELETE ')) { var path = url.substring(7); router.del(path, mapping[url]); console.log(`register URL mapping: DELETE ${path}`); } else { console.log(`invalid URL: ${url}`); } }}function addControllers(router, dir) { fs.readdirSync(__dirname + '/' + dir).filter((f) => { return f.endsWith('.js'); }).forEach((f) => { console.log(`process controller: ${f}...`); let mapping = require(__dirname + '/' + dir + '/' + f); addMapping(router, mapping); });}module.exports = function (dir) { let controllers_dir = dir || 'controllers', router = require('koa-router')(); addControllers(router, controllers_dir); return router.routes();};(2). rest.js--- 支持rest的中间件middlewarea.定义错误码的统一处理
b.统一输出REST
如果每个异步函数都编写下面这样的代码:
// 设置Content-Type:
ctx.response.type = 'application/json';// 设置Response Body:ctx.response.body = { products: products};很显然,这样的重复代码很容易导致错误,例如,写错了字符串'application/json',或者漏写了ctx.response.type = 'application/json',都会导致浏览器得不到JSON数据。写这个中间件给ctx添加一个rest()方法,直接输出JSON数据
module.exports = {
APIError: function (code, message) { this.code = code || 'internal:unknown_error'; this.message = message || ''; }, restify: (pathPrefix) => { pathPrefix = pathPrefix || '/api/'; return async (ctx, next) => { if (ctx.request.path.startsWith(pathPrefix)) { console.log(`Process API ${ctx.request.method} ${ctx.request.url}...`); ctx.rest = (data) => { ctx.response.type = 'application/json'; ctx.response.body = data; } try { await next(); } catch (e) { console.log('Process API error...'); ctx.response.status = 400; ctx.response.type = 'application/json'; ctx.response.body = { code: e.code || 'internal:unknown_error', message: e.message || '' }; } } else { await next(); } }; }};(3). controllers/api.js--- rest api的定义具体的api定义,这里可以优化下:不同模块建立文件夹,如products/Api.js, car/api.js ...这样更清晰
const products = require('../model/products');
const APIError = require('../rest').APIError;module.exports = { 'GET /api/products': async (ctx, next) => { ctx.rest({ products: products.getProducts() }); }, 'POST /api/products': async (ctx, next) => { var p = products.createProduct(ctx.request.body.name, ctx.request.body.manufacturer, parseFloat(ctx.request.body.price)); ctx.rest(p); }, 'DELETE /api/products/:id': async (ctx, next) => { console.log(`delete product ${ctx.params.id}...`); var p = products.deleteProduct(ctx.params.id); if (p) { ctx.rest(p); } else { throw new APIError('400', 'product not found by id.'); } }};(4). model/products.js--- 具体的model逻辑处理模拟数据库操作
// store products as database:
var id = 0;function nextId() { id++; return 'p' + id;}function Product(name, manufacturer, price) { this.id = nextId(); this.name = name; this.manufacturer = manufacturer; this.price = price;}var products = [ new Product('iPhone 7', 'Apple', 6800), new Product('ThinkPad T440', 'Lenovo', 5999), new Product('LBP2900', 'Canon', 1099)];module.exports = { getProducts: () => { return products; }, getProduct: (id) => { var i; for (i = 0; i < products.length; i++) { if (products[i].id === id) { return products[i]; } } return null; }, createProduct: (name, manufacturer, price) => { var p = new Product(name, manufacturer, price); products.push(p); return p; }, deleteProduct: (id) => { var index = -1, i; for (i = 0; i < products.length; i++) { if (products[i].id === id) { index = i; break; } } if (index >= 0) { // remove products[index]: return products.splice(index, 1)[0]; } return null; }};3、postman调试npm run dev
postman测试增、查、删
--------------------- 作者:空谷足音 -จุ 来源:CSDN 原文:https://blog.csdn.net/davidPan1234/article/details/83413958 版权声明:本文为博主原创文章,转载请附上博文链接!