0

大家早上好,我在设置服务器以侦听 webhook 数据并将其发布到数据库时遇到了一些困难。我主要是前端,所以其中一些对我来说有点新。所以我有一个建立在 snipcart 上的熟食网站。我有一个收据打印机,可以查询 api 并打印出新订单。所以我想要的是一个服务器来监听 webhook 并将信息存储在数据库中。我已经得到它正确侦听 webhook 的位置,但它拒绝发布到数据库。这是 app.js 文件中的代码。

'use strict';


require('./config/db');



const express = require('express');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');



const app = express();

var routes = require('./api/routes/apiRoutes');
routes(app);

let orderToken;

app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());

app.listen(process.env.PORT || 8080);


app.post('/hook', (req, res) => {
  orderToken = req.body.content.token;
  console.log(orderToken);
  const secret = "snipcart api key";

  const apiFetch = async function(){


  };

  let buffered = new Buffer.from(secret);
  let base64data = buffered.toString('base64');

  const start = async function(){



  const request = await fetch('https://app.snipcart.com/api/orders/'+orderToken, {
      headers: {
         'Authorization': `Basic ${base64data}`,
          'Accept': 'application/json'
      }
  });

  const result = await request.json();
    console.log(result);
  };

  start();

  res.status(200).end();
});


app.get('/', (req, res) => {
  res.send('hello world')
});

这是我的 apiController.js 文件中的代码


const mongoose = require('mongoose'),
      Order = mongoose.model('apiModel');


// listAllOrders function - To list all orders
exports.listAllOrders = (req, res) => {
api.find({}, (err, api) => {
if (err) {
res.status(500).send(err);
}
res.status(200).json(api);
});
};

// createNewOrder function - To create new Order
exports.createNewOrder = (req, res) => {
let  newApi = new api (req.body);
newApi.save((err, api) => {
if (err) {
res.status(500).send(err);
}
res.status(201).json(api);
});
};

// deleteOrder function - To delete order by id
exports.deleteOrder = async ( req, res) => {
await  api.deleteOne({ _id:req.params.id }, (err) => {
if (err) {
return res.status(404).send(err);
}
res.status(200).json({ message:"Order successfully deleted"});
});
};

和我的 apiModel.js 文件


const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const ApiSchema = new Schema({
  customerName: {
             type:String,
             required:true
         },
 customerPhone: {
           type:String,
           required:true
         },
  name: {
           type:String,
           required:true
       },
  orderNumber: {
           type:String,
           required:true
       },
  price: {
          type:String,
          required:true
       },
  customFields: {
        type:Array,
        required:false
        },
});

module.exports = mongoose.model("apiModel", ApiSchema);

apiRoutes.js




module.exports = function(app){
  var orderList = require('../controllers/apiController');


  app
  .route('/orders')
  .get(orderList.listAllOrders)
  .post(orderList.createNewOrder);


  app
  .route('/order/:id')
  .delete(orderList.deleteOrder);


};

和我的 db.js


const mongoose = require("mongoose");

//Assign MongoDB connection string to Uri and declare options settings
var  uri = "<mongodb atlas info> 
retryWrites=true&w=majority";

// Declare a variable named option and assign optional settings
const  options = {
useNewUrlParser:  true,
useUnifiedTopology:  true
};

// Connect MongoDB Atlas using mongoose connect method
mongoose.connect(uri, options).then(() => {
console.log("Database connection established!");
},
err  => {
{
console.log("Error connecting Database instance due to:", err);
}
});

这是我需要放入数据库的示例响应

{
    "token": "93c4604e-35ac-4db7-b3f1-2871476e9e6a",
    "creationDate": "2013-10-22T20:54:40.377Z",
    "modificationDate": "2013-10-22T20:55:45.617Z",
    "status": "Processed",
    "paymentMethod": "CreditCard",
    "invoiceNumber": "SNIP-1427",
    "email": "geeks@snipcart.com",
    "cardHolderName": "Geeks Snipcart",
    "creditCardLast4Digits": "4242",
    "billingAddressName": "Geeks Snipcart",
    "billingAddressCompanyName": "Snipcart",
    "billingAddressAddress1": "4885 1ere Avenue",
    "billingAddressAddress2": null,
    "billingAddressCity": "Quebec",
    "billingAddressCountry": "CA",
    "billingAddressProvince": "QC",
    "billingAddressPostalCode": "G1H2T5",
    "billingAddressPhone": "1-877-301-4813",
    "notes": null,
    "shippingAddressName": "Geeks Snipcart",
    "shippingAddressCompanyName": "Snipcart",
    "shippingAddressAddress1": "4885 1ere Avenue",
    "shippingAddressAddress2": null,
    "shippingAddressCity": "Quebec",
    "shippingAddressCountry": "CA",
    "shippingAddressProvince": "QC",
    "shippingAddressPostalCode": "G1H2T5",
    "shippingAddressPhone": "1-877-301-4813",
    "shippingAddressSameAsBilling": true,
    "finalGrandTotal": 287.44,
    "shippingFees": 10,
    "shippingMethod": "Shipping",
    "items": [
        {
            "uniqueId": "1aad3398-1260-419c-9af4-d18e6fe75fbf",
            "id": "1",
            "name": "Un poster",
            "price": 300,
            "quantity": 1,
            "url": "http://snipcart.com",
            "weight": 10,
            "description": "Bacon",
            "image": "",
            "customFieldsJson": "[]",
            "stackable": true,
            "maxQuantity": null,
            "totalPrice": 300,
            "totalWeight": 10
        },
        ...
    ],
    "taxes": [
        {
            "taxName": "TPS",
            "taxRate": 0.05,
            "amount": 12.5,
            "numberForInvoice": ""
        },
        {
            "taxName": "TVQ",
            "taxRate": 0.09975,
            "amount": 24.94,
            "numberForInvoice": ""
        },
        ...
    ],
    "rebateAmount": 0,
    "subtotal": 310,
    "itemsTotal": 300,
    "grandTotal": 347.44,
    "totalWeight": 10,
    "hasPromocode": true,
    "totalRebateRate": 20,
    "promocodes": [
        {
            "code": "PROMO",
            "name": "PROMO",
            "type": "Rate",
            "rate": 20,
        },
        ...
    ],
    "willBePaidLater": false,
    "customFields": [
        {
            "name":"Slug",
            "value": "An order"
        },
        ...
    ],
    "paymentTransactionId": null,
}

我不需要数据库中的所有信息,只需要一些关键项目,如客户姓名、电话号码和订单信息。但如果订单中有多个项目,我需要它考虑到这一点并添加订单中的所有项目。这是我需要集成的打印机的文档https://star-m.jp/products/s_print/CloudPRNTSDK/Documentation/en/index.html希望大家能给我任何帮助。谢谢!

4

1 回答 1

0

Snipcart将发送webhook给您endpoint不同的events。我建议您首先filter使用eventby eventName,因为您只想听order.completed事件。之后,从body请求消息中,您可以提取items将在req.body.content.items. 您可以从可用信息中获取您想要的信息,并将其仅存储在数据库中。

试试这个:

app.post('/hook', (req, res) => {

   if (req.body.eventName === 'order.completed') {

      const customer_name = req.body.content.cardHolderName;
      const customer_phone req.body.content.billingAddressPhone;
      const order_number = req.body.content.invoiceNumber;
      
      let items = [];
      req.body.content.items.forEach((item) => {
           items.push({
               name: item.name,
               price: item.price,
               quantity: item.quantity,
               id: item.uniqueId
           });
      })


      // Now store in database

      apiFetch.create({
          customerName: customer_name,
          customerPhone: customer_phone
          name: customer_name,
          orderNumber: order_number 
          customFields: items 
      }).then(()=>{
          res.status(200).json({success:true});
      }, (error)=>{
          console.log('ERROR: ', error);
      })
    
   }

};
于 2021-04-04T20:50:44.640 回答