zoukankan      html  css  js  c++  java
  • [转]nodeJs--koa2 REST API

    本文转自:https://blog.csdn.net/davidPan1234/article/details/83413958

    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.js


    const 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的中间件middleware

    a.定义错误码的统一处理

    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
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    springboot访问静态资源遇到的坑
    mysql存储过程
    sharding-jdbc数据分片配置
    sharding-jdbc springboot配置
    数据库分库分表配置sharding-jdbc
    mysql数据库分库分表shardingjdbc
    angluarJs与后台交互小案例
    angluarJs与后台交互get
    DE1-soc软件实验”hello_word"
    编译到底做什么
  • 原文地址:https://www.cnblogs.com/freeliver54/p/10565246.html
Copyright © 2011-2022 走看看