使用react native 創(chuàng)建一個(gè)屬于你自己的云備忘錄app~(A。用node搭個(gè)服務(wù),基礎(chǔ)篇)

前言

寫這個(gè)的初衷是由于現(xiàn)在的記事本app都太冗余了,我很喜歡google的keep,但要是想同步的話還要翻墻;有道云筆記又有些大,ui也不夠直觀,太辦公向了,寫博客我很喜歡,但隨手寫點(diǎn)備忘錄,還是顯得有點(diǎn)重。正好我使用react native也有一段時(shí)間了,學(xué)node一直也找不到自己喜歡的項(xiàng)目練手,不如就自己寫一個(gè)吧~

在寫這個(gè)項(xiàng)目之前,可以說(shuō)一點(diǎn)都不了解mongoDB,不了解他的數(shù)據(jù)結(jié)構(gòu);可以說(shuō)是一個(gè)完全的后端小白了。。

如果對(duì)這個(gè)項(xiàng)目有興趣的朋友可以在github上點(diǎn)下star,本人也會(huì)一直更新迭代~有疑問(wèn)和建議的朋友可以在評(píng)論區(qū)指出 ~嘻嘻

起步

先建個(gè)服務(wù)

// server.js
const express=require('express')
const app=express()

// 用于上傳筆記
app.get('/upload',(req,res)=>{
    res.send('uploaded!!')
})

const server=app.listen(8888,()=>{
    const host=server.address().address
    const port=server.address().port

    console.log(`the server is listening on ${host}:${port}`)
})

初始化路由

基本上有三個(gè)路由,上傳,刪除,查找

// server.js

// 上傳文章
app.get('/upload', (req, res) => {
  res.send('uploaded!!');
});

// 刪除文章
app.get('/delete', (req, res) => {
  res.send('delete!!');
});

// 按分類查找
app.get('/findByLabel', (req, res) => {
  res.send('findByLabel!!');
});

初始化數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)使用mongodb,我用的是node-mongodb-native作為引擎他是mongodb官方的node引擎,express官網(wǎng)上推薦的mongoskin,有一年多沒(méi)更新了就放棄了。

新建一個(gè)數(shù)據(jù)庫(kù)配置文件,

const { MongoClient } = require('mongodb');
const assert = require('assert');

// Connection URL
const url = 'mongodb://localhost:27017';

// Database Name
const dbName = 'memo';

function connectDB() {
  // Use connect method to connect to the server
  MongoClient.connect(url, (err, client) => {
    assert.equal(null, err);
    console.log('Connected successfully to server');

    const db = client.db(dbName);

    client.close();
  });
}

module.exports = { connectDB };

在server.js中引用這個(gè)模塊,啟動(dòng)服務(wù)后,終端打印了Connected successfully to server,即為連接成功。

自定義配置

將配置信息單獨(dú)放在一個(gè)文件夾中,方便維護(hù)。這里寫入了監(jiān)聽(tīng)端口和數(shù)據(jù)庫(kù)信息,如果有其他的,將在后面加入。

module.exports = {
  port: 8888,
  mongodb: 'mongodb://localhost:27017',
  dbName: 'memo',
};

使用promise重構(gòu)連接數(shù)據(jù)庫(kù)方法

查看了文檔,因?yàn)槠渌僮鲾?shù)據(jù)庫(kù)的api都依賴于MongoClient.connect方法中的回調(diào)函數(shù)中的參數(shù)client。因?yàn)椴僮鲾?shù)據(jù)庫(kù)復(fù)雜,為了使代碼更清晰,同時(shí)避免回調(diào)地獄,使用promise做個(gè)封裝,進(jìn)行鏈?zhǔn)秸{(diào)用。

// mongo.js
const connectDB = new Promise((resolve, reject) => {
  MongoClient.connect(mongodbURL, (err, client) => {
    if (err) {
      reject(err);
    } else {
      assert.equal(null, err);
      console.log('Connected successfully to server');

      const db = client.db(dbName);
      resolve(db);
    }
  });
});

module.exports = { connectDB };

調(diào)用:

connectDB.then((db) => {
  findDocuments(db);
});

編寫添加方法

基礎(chǔ)模板

const assert = require('assert');

const insertDocuments = function (db, callback = () => {}) {
  // Get the documents collection
  const collection = db.collection('documents');
  // Insert some documents
  collection.insertOne({ a: 'test' }, (err, result) => {
    assert.equal(err, null);
    assert.equal(1, result.result.n);
    assert.equal(1, result.ops.length);
    console.log('Inserted a document into the collection');
    callback(result);
  });
};

module.exports = { insertDocuments };

其他的操作,如刪除或查找,都可以在官方文檔上都可以找到,就不一一舉例了。

創(chuàng)建錯(cuò)誤實(shí)例

包括一個(gè)請(qǐng)求狀態(tài)碼和錯(cuò)誤碼

// createError.js
function createError(code = 1) {
  return {
    status: 1,// 1為錯(cuò)誤;0為成功
    code,
  };
}

module.exports = { createError };

我們?cè)倬帉憥讉€(gè)可能會(huì)出現(xiàn)的錯(cuò)誤實(shí)例,如:

// error.js
const errors = {
  CONNECT_DB_FAILED: 'CONNECT_DB_FAILED', // 連接數(shù)據(jù)庫(kù)失敗

};

稍微更改下connectDB的邏輯:

const connectDB = new Promise((resolve, reject) => {
  MongoClient.connect(mongodbURL, (err, client) => {
    if (err) {
      reject(createError(errors.CONNECT_DB_FAILED));
    } else {
      const db = client.db(dbName);
      resolve(db);
    }
  });
});

嘗試把config.js中的mongodbURL更改為錯(cuò)誤的地址,查看終端是否打印{ status: 1, code: 'CONNECT_DB_FAILED' }

用promise封裝添加方法

由于官方給出的代碼例子都是回調(diào)形式,代碼意圖不清晰,使用promise封裝,避免回調(diào)地獄。

const insertDocuments = (db, data = { test: 1 }, collectionName = 'documents') => new Promise((resolve, reject) => {
  const collection = db.collection(collectionName);
  collection.insertOne(data, (err, { result }) => {
    if (err) {
      reject(createError(errors.HANDLE_DB_FAILED));
    } else {
      resolve(createResult(result));
    }
  });
});

在index.js中,更改調(diào)用方式,終端會(huì)打印data { status: 0, body: { n: 1, ok: 1 } }。

connectDB
  .then(db => insertDocuments(db))
  .then(data => console.log('data', data))
  .catch((err) => {
    console.log(err);
  });

解析請(qǐng)求

我們發(fā)送的請(qǐng)求中的數(shù)據(jù),要放到req.body中去接收,這里需要安裝express的中間件bodyParser

const bodyParser = require('body-parser');
app.use(bodyParser.json({ extended: true }));

使用postman測(cè)試一下,發(fā)送請(qǐng)求{{URL}}/upload,body中寫入

{
    "context":"hello world"
}

我們編寫一下upload函數(shù),來(lái)打印一下

function upload(req, res) {
  const { context } = req.body;
  console.log(context) // hello world
  res.send('uploaded!!');
}

控制臺(tái)有輸出,則成功。

之后,把之前寫好的上傳函數(shù)寫入upload中。

function upload(req, res) {
  const { context } = req.body;
  connectDB
    .then(db => insertDocuments(db, context))
    .then(data => console.log('data', data))
    .catch((err) => {
      console.log(err);
    });
  res.send('uploaded!!');
}

執(zhí)行正常,則會(huì)返回{ status: 0, body: { n: 1, ok: 1 } }

錯(cuò)誤實(shí)例分類

在請(qǐng)求的過(guò)程中,可能會(huì)發(fā)生網(wǎng)絡(luò)錯(cuò)誤、數(shù)據(jù)庫(kù)錯(cuò)誤或是接口參數(shù)錯(cuò)誤;如果單純的返回一個(gè)錯(cuò)誤狀態(tài),整個(gè)服務(wù)就顯得太不可靠了。

在constants文件夾下創(chuàng)建一個(gè)錯(cuò)誤常量的對(duì)象,在后續(xù)的開(kāi)發(fā)過(guò)程中我們將加入更多的錯(cuò)誤類型,先簡(jiǎn)單寫這幾個(gè)

const errors = {
  CONNECT_DB_FAILED: 'CONNECT_DB_FAILED', // 連接數(shù)據(jù)庫(kù)失敗
  HANDLE_DB_FAILED: 'HANDLE_DB_FAILED', // 與數(shù)據(jù)庫(kù)操作時(shí)發(fā)生錯(cuò)誤
  INVALID_PARAMETERS: 'INVALID_PARAMETERS', // 參數(shù)錯(cuò)誤
  SYSTEM_ERROR: 'SYSTEM_ERROR', // 系統(tǒng)錯(cuò)誤,可能是語(yǔ)法,查看日志

};

module.exports = errors;

然后,我們?cè)賱?chuàng)建幾個(gè)錯(cuò)誤處理函數(shù),用于把錯(cuò)誤類型傳遞到響應(yīng)參數(shù)中。如下:

function parameterInvalid(res) {
  res.json(createError(INVALID_PARAMETERS));
}

function unknowError(err, res) {
  console.log(err);
  res.json(createError(SYSTEM_ERROR));
}

module.exports = { parameterInvalid, unknowError };

把上面的函數(shù)寫進(jìn)upload方法中:

const { parameterInvalid, unknowError } = require('../lib/handleErrors');

function upload(req, res) {
  const { context } = req.body;
  if (!context) {
    parameterInvalid(res);
    return;
  }

  connectDB
    .then(db => insertDocuments(db, { context }))
    .then(data => res.json(data))
    .catch((err) => { unknowError(err, res); });
}

以上,一個(gè)基礎(chǔ)的上傳服務(wù)就完成了~~ 還有其他的操作,如刪除、更新等,其實(shí)都大同小異,區(qū)別于node-mongo的api,大家可以查閱官方文檔或是查看項(xiàng)目源代碼~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容