javascript - 如何改进用于生产的节点 js 代码并在文件之间正确拆分?
问题描述
我是 javascript 和 node.js 的新手。
有人可以回答以下问题。1. 如何将 PostgreSQL 部分正确拆分到另一个文件中。2. 我的害虫实践是如何使用 pg 池。3. 我如何改进此代码以进行生产。
const express = require('express');
const app = express();
const pg = require('pg');
const pool = new pg.Pool({
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
});
app.get('/api/recipes', function(req, res){
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed '+ err);
res.status(400).send(err);
}
client.query('SELECT * FROM recipes;', function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
});
});
app.get('/api/recipes/:id', function(req, res){
var id = req.params.id;
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed ' + err);
res.status(400).send(err);
}
else{
client.query('SELECT * FROM recipes WHERE recipes_id = $1;', [id], function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
}
});
});
app.listen(3000,function(){
console.log('Server listen on port 3000');
});
解决方案
人们有很多方法可以拆分您描述的代码。我一块一块来。
首先,拉出任何可配置的变量并设置一个可以从环境中获取它们的文件(可能使用开发默认值,您可以选择)。你可以使用像commands或convict这样的库,但老实说,我更喜欢自己编写一个简单的文件来拉取它们:
// ./config.js
module.exports = {
pool: {
user: process.env.DB_USER || 'admin',
password: process.env.DB_PW || 'test123!',
host: process.env.DB_HOST || '127.0.0.1',
port: process.env.DB_PORT || '5432',
database: process.env.DB_NAME || 'test_db'
}
};
至于您的数据库调用,有些人喜欢使用类似 ORM 的东西,例如sequelize,但我还是倾向于从简单开始并根据需要添加东西。在您的情况下,您应该考虑可以制作通用代码的样板文件,然后将它们包装到仅公开给它真正需要的调用代码的简单模块中。例如,您会注意到您的大多数路由将连接到池,测试错误,然后运行查询(如果没有出错),最后呈现错误或查询结果,对吗?因此,这一切都可以包装到一个相当简单的查询函数中,该函数在内部处理样板文件,并且只使用查询表达式和回调,例如:
// ./db/index.js
const pg = require('pg');
const config = require('./config');
const pool = new pg.Pool(config.pool);
function query(sql, params, callback) {
// maybe check for valid inputs here or something, but at least normalize in case folks don't pass params
if(arguments.length < 3) {
callback = params;
params = null;
}
pool.connect((err, client, done) => {
// just exit here and let the calling code know there was a problem
if(err) return callback(err);
// I haven't tested this w/ the pg library recently, you might have to do two of these if it doesn't like null as a second argument
client.query(sql, params, (err, result) => {
if(err) return callback(err);
done();
// calling code probably doesn't care about anything but rows, but you can do other stuff here if you prefer
return callback(null, result.rows);
});
});
};
// You can also add additional functions if you want shorthand for doing things like query by ID or with params, or similar
module.exports = { query };
我还认为将 SQL 字符串集中存储在某个地方或模型对象上会很有帮助,只是为了让路由代码注释必须关心这一点。对于使用您的两条路线的超级简单示例,我可能会执行以下操作:
// ./db/queries.js
module.exports = {
RECIPES: {
LIST: 'SELECT * FROM recipes;',
FIND_BY_ID: 'SELECT * FROM recipes WHERE recipes_id = $1;'
}
};
好的,所以现在您的路由代码可以非常简单,您只需获取 db 模块并处理查询,让路由担心它与请求和响应有什么关系。人们喜欢的另一种选择是为您的应用程序中的每个模型(例如食谱)实际创建一个模块,将上述两个文件包装成一组静态函数,这样您的路由甚至不知道它们正在专门查询。在这种情况下,调用将类似于Recipe.list(cb)
or Recipe.findById(id, cb)
。这是几年前 Ruby on Rails 流行起来的一种风格,它在 Node 社区中的接受程度参差不齐,但为了完整起见,我提到它。
// ./routes/recipes.js
const router = require('express').Router();
const db = require('./db');
const queries = require('./db/queries');
router.get('/api/recipes', (req, res, next) => {
db.query(queries.RECIPES.LIST, (err, rows) => {
if(err) return next(err);
return res.send(rows); // status 200 is the default here
});
});
router.get('/api/recipes/:id', (req, res, next) => {
const id = req.params.id;
db.query(queries.RECIPES.FIND_BY_ID, [id], (err, rows) => {
if (err) return next(err);
return res.send(rows);
});
});
最后,在您的主 Express 设置文件中:
// ./app.js
const express = require('express');
const app = express();
const recipeRoutes = require('./routes/recipes') // note if you have an index.js file that gets imported just by calling for the folder, so that's a way to group features as well
app.use(recipeRoutes);
// I'm a big fan of error handling middleware. There's a more complex approach I did in [praeter][4] that gives you http-verb based errors that you can then catch and send the appropriate status, but that's again more complex than you might need here.
app.use((err, req, res, next) => {
// this can be as simple or as complex as you like.
// note it's a best practice to send only "clean" messages to the client, so you don't give away that you're using a Postgres db or other stuff that makes hacking easier.
console.error(err);
res.status(500).send('Oops! Something went wrong!!');
});
显然,有很多方法可以给这只猫剥皮,所以我建议主要是寻找你在哪里重复自己,然后重构以减少重复。此外,如果您有兴趣制作更多的生产就绪应用程序,那么12 要素应用程序是必读的。
推荐阅读
- html - flex-shrink 是否有任何限制?
- javascript - 包括用于打字稿测试的 js 文件
- solidity - 尝试调用智能合约的另一个功能时出现问题
- git - 如何在 IntelliJIDEA 中保持分支分离?
- django-orm - 在 Django ORM 中加入子查询表
- java - 制作安卓电视启动器应用程序需要什么
- wordpress - 限制通过电子邮件在 Wordpress 中提交表单
- javascript - 未找到模块:无法解析“E:\frontend\node_modules\@mui\styled-engine”中的“@emotion/react”
- c# - 无法更新数据库中的现有条目
- c# - 无法在 C# 中实现 COM 接口