在expressjs中创建模型

时间:2016-10-19 04:19:01

标签: javascript node.js express models

我有一个快速应用程序从外部API获取其数据

api.com/companies (GET, POST)
api.com/companies/id (GET, PUT)

我想创建一个模型来使代码更容易维护,因为你可以看到我在这里重复了很多代码。

router.get('/companies', function(req, res, next) {

    http.get({
        host: 'http://api.com',
        path: '/companies'
    }, function(response) {
        var body = '';
        response.on('data', function(d) {
            body += d;
        });
    });

    res.render('companies', {data: body});
});

router.get('/companies/:id', function(req, res, next) {

    http.get({
        host: 'http://api.com',
        path: '/companies/' + req.params.id
    }, function(response) {
        var body = '';
        response.on('data', function(d) {
            body += d;
        });
    });

    res.render('company', {data: body});
});

我该怎么做?

3 个答案:

答案 0 :(得分:2)

在这种情况下无需多条路线!您可以使用来使用可选参数。看一下下面的例子:

<ImageView
    android:id="@+id/center_view"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_centerInParent="true"
    android:background="@color/black" />


<View
    android:id="@+id/view_center_top"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:layout_above="@+id/center_view"
    android:layout_marginBottom="20dp" />


<View
    android:id="@+id/view_center_bottom"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:layout_below="@+id/center_view"
    android:layout_marginTop="20dp" />

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="130dp"
    android:layout_alignParentLeft="true"
    android:layout_centerVertical="true"
    android:layout_marginLeft="10dp">

    <ImageView
        android:id="@+id/view_1"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_above="@+id/view_0_left"

        android:background="@color/black" />

    <View
        android:id="@+id/view_0_left"
        android:layout_width="5dp"
        android:layout_height="5dp"
        android:layout_centerVertical="true"
        android:background="@color/green" />

    <ImageView
        android:id="@+id/view_2"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@+id/view_0_left"
        android:layout_centerVertical="true"
        android:background="@color/black" />
</RelativeLayout>


<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="130dp"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:layout_marginRight="10dp">

    <ImageView
        android:id="@+id/view_11"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_above="@+id/view_0_right"
        android:background="@color/black" />

    <View
        android:id="@+id/view_0_right"
        android:layout_width="5dp"
        android:layout_height="5dp"
        android:layout_centerVertical="true"
        android:background="@color/green" />

    <ImageView
        android:id="@+id/view_22"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@+id/view_0_right"
        android:layout_centerVertical="true"
        android:background="@color/black" />
</RelativeLayout>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/view_center_top"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="5dp">

    <ImageView
        android:id="@+id/view_111"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@color/black" />

    <View
        android:layout_width="5dp"
        android:layout_height="5dp"
        android:background="@color/green" />

    <ImageView
        android:id="@+id/view_222"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@color/black" />
</LinearLayout>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/view_center_bottom"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="5dp">

    <ImageView
        android:id="@+id/view_1111"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@color/black" />

    <View
        android:layout_width="5dp"
        android:layout_height="5dp"
        android:background="@color/green" />

    <ImageView
        android:id="@+id/view_2222"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="@color/black" />
</LinearLayout>

这里有一些代码:

router.get('/companies/:id?', function(req, res, next) {
    var id = req.params.id;

    http.get({
        host: 'http://api.com',
        path: '/companies/' + id ? id : ""
    }, function(response) {
        var body = '';
        response.on('data', function(d) {
            body += d;
        });
    });

    res.render('companies', {data: body});
});

使用内联if语句,所以它的含义是, if path: '/companies/' + id ? id : "" ,将id添加到id != null, false, or undefined字符串和 else < / strong>根本不添加任何东西。

修改

关于js类,你可以这样做:

companies/

您的路由器类可以像这样使用此类:

// Seperate into a different file and export it
class Companies { 
    constructor (id) {
        this.id= id;
        this.body = "";
        // You can add more values for this particular object
        // Or you can dynamically create them without declaring here 
        // e.g company.new_value = "value"
    }

    get (cb) {
        http.get({
            host: 'http://api.com',
            path: '/companies/' + this.id ? this.id : ""
        }, function(response) {
            response.on('data',(d) => {
                this.body += d;
                cb (); // callback
            });
        }); 
    }

    post () {
        // You can add more methods ... E.g  a POST method.
    }
    put (cb) {
        http.put({
            host: 'http://api.com',
            path: '/companies/' + this.id ? this.id : "",
            ... Other object values here ...
        }, function(response) {
            response.on('data',(d) => {
                ... do something here with the response ...
                cb(); //callback 
            });
        }); 
    }
}

我为了简单起见在这里添加了回调,但我建议使用promises: https://developers.google.com/web/fundamentals/getting-started/primers/promises

答案 1 :(得分:2)

首先: http.get是异步的。经验法则:当您看到回调时,您正在处理异步函数。您无法判断,当您使用res.render终止请求时,是否将完成http.get()及其回调。 这意味着res.render总是需要在回调中发生。

我在此示例中使用ES6语法。

// request (https://github.com/request/request) is a module worthwhile installing. 
const request = require('request');
// Note the ? after id - this is a conditional parameter
router.get('/companies/:id?', (req, res, next) => {

    // Init some variables
    let url = ''; 
    let template = ''

    // Distinguish between the two types of requests we want to handle
    if(req.params.id) {
        url = 'http://api.com/companies/' + req.params.id;
        template = 'company';
     } else {
        url = 'http://api.com/companies';
        template = 'companies';
     }

    request.get(url, (err, response, body) => {

        // Terminate the request and pass the error on
        // it will be handled by express error hander then
        if(err) return next(err);
        // Maybe also check for response.statusCode === 200

        // Finally terminate the request
        res.render(template, {data: body})
    });

});

关于你的“模特”问题。 我宁愿称它们为“服务”,因为模型是一些数据集合。服务是逻辑的集合。

要创建公司服务模块,请执行以下操作:

// File companyService.js
const request = require('request');

// This is just one of many ways to encapsulate logic in JavaScript (e.g. classes)
// Pass in a config that contains your service base URIs
module.exports = function companyService(config) {
    return {
        getCompanies: (cb) => {
            request.get(config.endpoints.company.many, (err, response, body) => {
                return cb(err, body);
            });
        },
        getCompany: (cb) => {
            request.get(config.endpoints.company.one, (err, response, body) => {
                return cb(err, body);
            });
        },
    }
};


// Use this module like
const config = require('./path/to/config');
const companyService = require('./companyService')(config);

// In a route
companyService.getCompanies((err, body) => {
    if(err) return next(err);

    res.render(/*...*/)
});

答案 2 :(得分:1)

进行重构的一般方法是确定代码中的不同之处,并将其提取为传递到包含公共代码的函数的动态部分。

例如,这里不同的两件事是请求发生的路径

'/companies' vs '/companies/:id'

传递给http.get

的相关路径
'/companies' vs '/companies/' + req.params.id

您可以提取这些并将它们传递给将为您分配处理程序的函数。

这是一种通用方法:

// props contains the route and 
// a function that extracts the path from the request
function setupGet(router, props) {
  router.get('/' + props.route, function(req, res, next) {

    http.get({
      host: 'http://api.com',
      path: props.getPath(req)
    }, function(response) {
      var body = '';
      response.on('data', function(d) {
        body += d;
      });
    });

    res.render('company', {
      data: body
    });
  });
}

然后用两个选项调用它:

setupGet(router, { 
  route: 'companies', 
  getPath: function(req) {
    return 'companies';
  }
});

setupGet(router, { 
  route: 'companies/:id', 
  getPath: function(req) {
    return 'companies' + req.params.id;
  }
});

这样做的好处是,您可以使用路径和路径的任意组合,也可以使用其他req属性来确定路径。

您需要意识到的另一件事是,res.render调用将在您执行body += d之前发生,因为前者在调用{{1}之后同步发生而后者是异步发生的(稍后会发生)。

您可能希望将http.get方法放在回调本身中。

render