为了账号安全,请及时绑定邮箱和手机立即绑定

Rollup+Restify+typescript+mongodb开发后端http服务

标签:
AngularJS

背景:

向小程序,提供http/https接口服务,存储用户数据、日志数据。

技术选型

resitify

纯粹的http服务,不涉及视图

typescript 2.1+

类型校验,规范代码

mock.js

提供mock服务

mongodb

文档结构,存储数据

rollup

js管理

node

后端服务管理

pm2

后端node进程管理

环境搭建

安装node

默认已安装node,当前使用版本v10.16.3。

初始化工程

npm init -y

//得到如下package.json:
{
  "name": "restify-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "

安装依赖

//产线环境使用
 npm install --save mongodb restify mockjs  pm2
//开发环境使用
## 安装 rollup.js 基础模块
npm i --save-dev rollup rollup-plugin-buble

## 安装 rollup.js 编译代码混淆插件
npm i --save-dev rollup-plugin-uglify

## 安装 rollup.js 编译 Typescript 代码的插件模块
npm i --save-dev rollup-plugin-typescript typescript tslib

安装后package.json

{
  "name": "restify-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "rollup -c rollup.config.js",
    "start":"node dist/app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mockjs": "^1.1.0",
    "mongodb": "^3.3.4",
    "pm2": "^4.1.2",
    "restify": "^8.4.0"
  },
  "devDependencies": {
    "rollup": "^1.27.2",
    "rollup-plugin-buble": "^0.19.8",
    "rollup-plugin-typescript": "^1.0.1",
    "rollup-plugin-uglify": "^6.0.3",
    "tslib": "^1.10.0",
    "typescript": "^3.7.2"
  }
}

配置rollup

touch rollup.config.js 

const path = require('path');
const buble = require('rollup-plugin-buble'); 
const typescript = require('rollup-plugin-typescript');

const resolveFile = function(filePath) {
  return path.join(__dirname, filePath)
}

module.exports = [
  {
    input: resolveFile('src/main.ts'),
    output: {
      file: resolveFile('dist/app.js'),
      format: 'cjs',
      name: 'restify-demo',
    }, 
    plugins: [
      typescript(),
      buble(),
    ],
  },
]

安装mongodb

下载mongo

# 进入 /usr/local
cd /usr/local

# 下载
sudo curl -O https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.9.tgz

# 解压
sudo tar -zxvf mongodb-osx-ssl-x86_64-4.0.9.tgz

# 重命名为 mongodb 目录

sudo mv mongodb-osx-x86_64-4.0.9/ mongodb

export PATH=/usr/local/mongodb/bin:$PATH

添加mongo.conf

# 日志
systemLog:
# 日志为文件
  destination: file
# 文件位置
  path: /usr/local/var/log/mongodb/mongo.log
# 是否追加
  logAppend: true
#进程
processManagement:
# 守护进程方式
  fork: true
storage:
  dbPath: /usr/local/var/mongodb
net:
# 绑定IP,默认127.0.0.1,只能本机访问
  bindIp: 127.0.0.1
# 端口
  port: 27017

运行mongod

mongod --config /usr/local/etc/mongo.conf

校验mongo

> mongo 
MongoDB shell version v4.0.9
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("07aaf4a0-c188-4d50-9412-96a2b0625e8a") }
MongoDB server version: 4.0.9
Server has startup warnings: 
2019-11-27T17:31:59.406+0800 I CONTROL  [initandlisten] 
2019-11-27T17:31:59.407+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2019-11-27T17:31:59.408+0800 I CONTROL  [initandlisten] **

hello-world

import restify from "restify";
import { Server } from "restify/lib/server";

function respond(req, res, next) {
  res.send('hello ' + req.params.name);
  next();
}

const server:Server = restify.createServer();
server.get('/hello/:name', respond);
server.head('/hello/:name', respond);

server.listen(8090, function() {
  console.log('%s listening at %s', server.name, server.url);
});

hello-world请求

curl -is http://localhost:8090/hello/world -H 'accept: text/plain'
## 返回
'accept: text/plain'
HTTP/1.1 200 OK
Server: restify
Content-Type: text/plain
Content-Length: 11
Date: Wed, 20 Nov 2019 05:35:12 GMT
Connection: keep-alive

hello world

业务实践

依赖引入

import restify from "restify";
import { Server } from "restify/lib/server";
import Mock from 'mockjs'
import { dbConnect } from "./utils";
const mongodb = require('mongodb');
const log4js = require('log4js');

const logger = log4js.getLogger();
const server:Server = restify.createServer();
//before route choose 
server.pre(restify.plugins.pre.userAgentConnection());
//after router choose ,before handler
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser({ mapParams: false }));
server.use(restify.plugins.bodyParser());

restify 路由配置

//set route 
server.post('/add',
  async function(req, res, next) {
    const desc = req.body.desc;
    let result = await create(desc);
    req.desc = {desc:'success',data:{
      desc:result,
      numbrer:Mock.mock({
        "number|1-100": 100
      })
    }};
    return next();
  },
  function(req, res, next) {
    res.send(req.desc);
    return next();
  }
);
server.get(
  '/all',
  async function(req, res, next) {
    let result = await fetchAll();
    req.desc = result;
    return next();
  },
  function(req, res, next) {
      res.send(req.desc);
      return next();
  }
)

api版本支持

function sendV1(req, res, next) {
  const mockNumber = Mock.mock({
    "number|1-100": 100
  });
  res.send(`version number:${mockNumber} with param ${req.params.name}`);
  return next();
}

function sendV2(req, res, next) {
  const mockNumber = Mock.mock({
    "number|1-100": 100
  });
  res.send({ param: req.params.name,version: mockNumber});
  return next();
}

server.get('/version/:name', restify.plugins.conditionalHandler([
  { version: '1.1.3', handler: sendV1 },
  { version: ['2.0.0', '2.1.0', '2.2.0'], handler: sendV2 }
]));

mongo 操作

let db;
 
// Get a DB connection when this module is loaded
(function getDbConnection() {
    dbConnect().then((database) => {
        db = database;
    }).catch((err) => {
        logger.error('Error while initializing DB: ' + err.message, 'lists-dao-mongogb.getDbConnection()');
    });
})();

function create(description) {
      return new Promise((resolve, reject) => {
           let lists = db.collection('shoppingLists');
           let listId = mongodb.ObjectId();
           let whenCreated = Date.now();
          let item = {
               _id: listId,
               id: listId,
               description: description,
               whenCreated: whenCreated,
               whenUpdated: null
           };
           lists.insertOne(item, (err, result) => {
               if (err) {
                   logger.error('Error occurred: ' + err.message, 'create()');
                   reject(err);
               } else {
                   resolve({ data: { createdId: result.insertedId }, statusCode: 201 });
               }
           });
       });
}

function fetchAll() {
       return new Promise((resolve, reject) => {
           let lists = db.collection('shoppingLists');
           lists.find({}).toArray((err, documents) => {
               if (err) {
                   logger.error('Error occurred: ' + err.message, 'fetchAll()');
                   reject(err);
               } else {
                   logger.debug('Raw data: ' + JSON.stringify(documents), 'fetchAll()');
                   resolve({ data: JSON.stringify(documents), statusCode: (documents.length > 0) ? 200 : 404 });
               }
           });
       });
}

db连接

const mongodb = require('mongodb');
const log4js = require('log4js');
const logger = log4js.getLogger();
// logger.level = 'debug';

let mongodbClient;
let db;

const appSettings = {
    mongodb_url:'mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb',
    mongodb_db_name:'mongoDemo',
}
function dbClose() {
    if (mongodbClient && mongodbClient.isConnected()) {
        mongodbClient.close();
    }
}

export function dbConnect() {
    return new Promise((resolve, reject) => {
        if (db) {
            resolve(db);
        } else {
            mongodb.MongoClient.connect(appSettings.mongodb_url, function(err, client) {
                if (err) {
                    logger.error('Error connecting to the MongoDB URL: ' + appSettings.mongodb_url);
                    reject(err);
                }
                mongodbClient = client;
                db = mongodbClient.db(appSettings.mongodb_db_name);
                // Make sure connection closes when Node exits
                process.on('exit', (code) => {
                    dbClose();
                })
                resolve(db);
            });
        }
    });
}

参考文献

本文作者:前端首席体验师(CheongHu)

联系邮箱:simple2012hcz@126.com

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
0
获赞与收藏
22

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消