2016-10-19 15 views
5

Tôi có một ứng dụng nhanh mà được dữ liệu của mình từ một API bên ngoàitạo mô hình trong expressjs

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

Tôi muốn tạo ra một mô hình để làm cho đoạn code dễ dàng hơn để duy trì như bạn có thể nhìn thấy Tôi đang lặp đi lặp lại rất nhiều mã ở đây.

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}); 
}); 

Tôi làm như thế nào?

Trả lời

1

Trước hết: http.get không đồng bộ. Quy tắc chung: Khi bạn nhìn thấy một cuộc gọi lại, bạn đang xử lý một hàm không đồng bộ. Bạn không thể nói, nếu http.get() và gọi lại của nó sẽ được hoàn thành khi bạn chấm dứt yêu cầu với res.render. Điều này có nghĩa là res.render luôn luôn cần phải xảy ra trong cuộc gọi lại.

Tôi đang sử dụng cú pháp ES6 trong ví dụ này.

// 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}) 
    }); 

}); 

Về câu hỏi 'mô hình' của bạn. Tôi thà gọi chúng là 'dịch vụ' làm mô hình là một số tập hợp dữ liệu. Một dịch vụ là một tập hợp logic.

Để tạo một mô-đun dịch vụ công ty làm điều gì đó như thế:

// 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(/*...*/) 
}); 
1

Cách chung để tiếp cận tái cấu trúc là xác định những gì khác nhau trong mã của bạn và giải nén đó là một phần động được chuyển vào một hàm có chứa mã chung.

Ví dụ, hai điều đó là khác nhau ở đây là con đường mà trên đó các yêu cầu xảy ra

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

Và con đường liên quan mà được thông qua để http.get

'/companies' vs '/companies/' + req.params.id 

Bạn có thể trích xuất những điều này và chuyển chúng vào một hàm sẽ gán một trình xử lý cho bạn.

Dưới đây là một cách tiếp cận chung:

// 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 
    }); 
    }); 
} 

Và sau đó gọi nó với hai lựa chọn:

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

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

Lợi ích ở đây là bạn có thể sử dụng bất kỳ sự kết hợp của các tuyến đường và các đường dẫn cũng như sử dụng khác req thuộc tính để xác định đường dẫn.

Một điều bạn cần phải nhận thức được rằng cuộc gọi res.render của bạn sẽ xảy ra trước bạn làm body += d, bởi vì trước đây xảy ra đồng bộ ngay sau khi cuộc gọi đến http.get và sau này xảy ra không đồng bộ (đôi khi sau này).

Bạn có thể muốn đặt phương thức render trong chính cuộc gọi lại.

// 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; 

     // probably want to render here 
     res.render('company', { 
      data: body 
     }); 
     }); 
    }); 
    }); 
} 
+0

điểm tốt. Tôi vẫn đang sử dụng công cụ async này tôi sẽ không thể tạo một mô hình để tôi có thể gọi/các công ty trong nhiều trang? Tôi yêu cầu vì async sẽ cần phải hoàn thành yêu cầu-phản ứng để có được dữ liệu. mỗi lần tôi sẽ cần phải hiển thị tất cả các công ty tôi sẽ cần phải thực hiện một yêu cầu http và gửi dữ liệu trong cuộc gọi lại? – handsome

+0

Vâng, nếu các công ty không thay đổi, bạn có thể lưu trữ chúng trong bộ nhớ ở đâu đó và thực hiện yêu cầu lần đầu tiên, lưu các công ty, và sau đó mỗi lần sau đó chỉ trả lại giá trị đã lưu. Bạn có muốn tôi chỉnh sửa câu hỏi của tôi và cho bạn xem một ví dụ không? – nem035

+0

có ý nghĩa nhưng tôi đang tìm kiếm một cái gì đó nhiều mô hình theo định hướng, như PHP cũ tốt để tôi có thể tái sử dụng logic thay vì làm cho tất cả những cuộc gọi http ở khắp mọi nơi. cảm ơn người đàn ông! – handsome

2

Không cần phải có nhiều tuyến đường trong trường hợp này! Bạn có thể sử dụng thông số tùy chọn bằng cách sử dụng ?. Hãy xem ví dụ sau:

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}); 
}); 

Các bit của mã ở đây:

path: '/companies/' + id ? id : "" 

là sử dụng một inline câu lệnh if, vì vậy những gì nó nói là, nếuid != null, false, or undefined, thêm id vào companies/ chuỗi và else chỉ cần thêm không có gì.

Sửa

Về lớp js, bạn có thể làm một cái gì đó như thế này:

// 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 
      }); 
     }); 
    } 
} 

lớp router của bạn sau đó có thể sử dụng lớp này như sau:

router.get('/companies/:id?', function(req, res, next) { 
    var id = req.params.id; 
    var company = new Companies(id); 
    company.get(() => { 
     // We now have the response from our http.get 
     // So lets access it now! 
     // Or run company.put(function() {...}) 
     console.log (company.body); 
     res.render('companies', {data: company.body}); 
    }); 

}); 

Tôi đã thêm callbacks ở đây để đơn giản nhưng tôi khuyên bạn nên sử dụng lời hứa: https://developers.google.com/web/fundamentals/getting-started/primers/promises

+0

yup bạn đúng, điều này có thể được đơn giản hóa rất nhiều với cách tiếp cận của bạn Tôi đang tìm kiếm một cái gì đó như 'var data = new companies()' hoặc 'var data = new companies (1)' và các công ty này() sẽ thực hiện phép thuật để đưa ra yêu cầu http và lấy dữ liệu. vì vậy tôi có thể tái sử dụng nó ở nhiều nơi hơn. cảm ơn!! – handsome

+0

Không phải lo lắng và chúc may mắn :) Vâng, bạn có thể thực hiện logic này thành một lớp học khá dễ dàng! Tôi sẽ thử thêm một ví dụ nhỏ. Hãy nhớ +1/chấp nhận nếu nó đã giúp: D @handsome – James111

+0

@handsome Hãy xem bản cập nhật của tôi. Nó sử dụng các nút es6 nút :) – James111

Các vấn đề liên quan