Chuyển tới nội dung chính

Chuẩn bị backend

Trong tutorial này, chúng ta sẽ sử dụng Express để làm server. Nếu bạn sử dụng một framework hoặc ngôn ngữ lập trình khác, bạn có thể tham khảo các logic được sử dụng.

Lưu ý

Để giữ cho tutorial dễ hiểu và tập trung vào phần tích hợp với CheckoutSDK, tất cả code server sẽ được viết trong một file duy nhất và nằm trong cùng repository với frontend. Thay vì sử dụng SQL hoặc NoSQL, chúng ta sẽ dùng lowdb để lưu cơ sở dữ liệu vào một file JSON. Đây không phải là best practice cho một backend thực tế.

Cài đặt các package cần thiết

Mở terminal lên và chạy các lệnh sau:

npm i express cors dotenv lowdb axios
npm i -D tsx @types/express @types/cors

Dựng server

Bên trong folder src, tạo 1 file backend.ts với nội dung bên dưới

src/backend.ts
import express from "express";
import { config } from "dotenv";

config();
const port = process.env.PORT || 10000;

express()
.get("/", async (req, res) => {
res.json({
message: "Đây là backend cho Checkout SDK Tutorial!",
});
})
.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

Bên trong package.json, thiết lập scripts, thêm script mới với nội dung như sau:

package.json
  "scripts": {
+ "backend": "tsx src/backend.ts"
},

Mở terminal lên và chạy lệnh npm run backend, bạn sẽ thấy server được chạy và lắng nghe requests trên port 10000:

$ npm run backend

> checkout-sdk-tutorial@1.0.0 backend
> tsx src/backend.ts

Server running at http://localhost:10000
$ curl localhost:10000
{"message":"Đây là backend cho Checkout SDK Tutorial!"}

Thiết lập CORS

Để cho phép gọi requests từ Zalo Mini App, bạn cần thiết lập CORS cho server. Nếu thiếu bước này, bạn sẽ gặp một lỗi rất phổ biến là Network Error. Thiết lập CORS cho server Express khá đơn giản:

src/backend.ts
  import express from "express";
+ import cors from "cors";
import { config } from "dotenv";

config();
const port = process.env.PORT || 10000;

express()
+ .use(cors({ origin: ["https://h5.zdn.vn", "http://localhost:3000"] }))
.get("/", async (req, res) => {
res.json({
message: "Đây là backend cho Checkout SDK Tutorial!",
});
})
.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

Thiết lập Database

Chúng ta sẽ sử dụng lowdb để lưu thông tin đơn hàng vào một file JSON. Trong thực tế, bạn sẽ muốn lưu vào một SQL hoặc NoSQL Database.

src/backend.ts
  import express from "express";
import cors from "cors";
import { config } from "dotenv";
+ import { LowSync } from "lowdb";
+ import { JSONFileSync } from "lowdb/node";
+ import { Order as OrderInfo } from "./types";
+
+ interface Order {
+ id: number;
+ zaloUserId: string;
+ checkoutSdkOrderId?: number;
+ info: OrderInfo;
+ }
+ interface Schema {
+ orders: Order[];
+ }

config();
const port = process.env.PORT || 10000;
+ const db = new LowSync(new JSONFileSync<Schema>("db.json"), { orders: [] });
+ db.read();

express()
.use(cors({ origin: ["https://h5.zdn.vn", "http://localhost:3000"] }))
.get("/", async (req, res) => {
res.json({
message: "Đây là backend cho Checkout SDK Tutorial!",
});
})
+ .get("/orders", async (req, res) => {
+ const allOrders = db.data.orders;
+ const orderInfos = allOrders.map((order) => order.info).reverse();
+ res.json(orderInfos);
+ })
.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

Thiết lập cần thiết cho template ZaUI Market

Khi sử dụng template ZaUI Market, backend của bạn cần phải implement ít nhất các endpoints sau:

  • GET /categories
  • GET /products
  • GET /banners
  • GET /stations
  • GET /orders

Chúng ta đã có endpoint cho GET /orders, nhưng các endpoints còn lại chưa được implement. Trong tutorial này, chúng ta sẽ sử dụng mock data có sẵn trong template để trả về dữ liệu cho các endpoints còn lại.

src/backend.ts
  import express from "express";
import cors from "cors";
import { config } from "dotenv";
import { LowSync } from "lowdb";
import { JSONFileSync } from "lowdb/node";
import { Order as OrderInfo } from "./types";

interface Order {
id: number;
zaloUserId: string;
checkoutSdkOrderId?: number;
info: OrderInfo;
}

interface Schema {
orders: Order[];
}

config();
const port = process.env.PORT || 10000;
const db = new LowSync(new JSONFileSync<Schema>("db.json"), { orders: [] });
db.read();

express()
.use(cors({ origin: ["https://h5.zdn.vn", "http://localhost:3000"] }))
.get("/", async (req, res) => {
res.json({
message: "Đây là backend cho Checkout SDK Tutorial!",
});
})
+ .get("/products", async (req, res) => {
+ res.json((await import("./mock/products.json")).default);
+ })
+ .get("/categories", async (req, res) => {
+ res.json((await import("./mock/categories.json")).default);
+ })
+ .get("/banners", async (req, res) => {
+ res.json((await import("./mock/banners.json")).default);
+ })
+ .get("/stations", async (req, res) => {
+ res.json((await import("./mock/stations.json")).default);
+ })
.get("/orders", async (req, res) => {
const allOrders = db.data.orders;
const orderInfos = allOrders.map((order) => order.info).reverse();
res.json(orderInfos);
})
.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

Deploy lên server

Bạn không thể chạy backend này ở localhost vì Checkout SDK yêu cầu Mini App phải được chạy bên trong ứng dụng Zalo. Hiện có nhiều hosting provider hỗ trợ deploy app Express lên server. Lưu ý rằng sau khi deploy, backend của bạn phải có domain và sử dụng HTTPS. Ví dụ: https://checkout-sdk-tutorial.onrender.com.

Thiết lập server API url cho Mini App

Sau khi deploy, bạn sẽ nhận được một URL để gọi API từ Mini App. Bước cuối cùng là cấu hình URL này để các requests đến backend đều sử dụng nó. Template ZaUI Market cho phép thay đổi thiết lập này bên trong app-config.json như sau:

app-config.json
  {
"template": {
"name": "zaui-market",
+ "apiUrl": "https://checkout-sdk-tutorial.onrender.com",

Vậy là chúng ta đã có một backend cơ bản để bắt đầu tích hợp Checkout SDK cho Zalo Mini App. Code mẫu cuối cùng sẽ trông như sau: backend.ts.