Skip to content

Dashboard

Xây dựng REST API với Firebase cloud functions, firestore và expressjs.

Created by Admin

Firebase là một trong những nền tảng cung cấp giải pháp hàng đầu để xây dựng Severless apps. Nó cung cấp cho ta những cách đơn giản để xây dựng và phát triển các ứng dụng mà không cần phải lo lắng đến chi phí thiết lập và bảo trì máy chủ trong thời gian dài kể từ khi bắt đầu. Firebase cũng cung cấp khả năng tích hợp với các dịch vụ khác của google như Google analytics, firestore db...
Trong bài viết này chúng ta sẽ đi xây dựng REST API với firebase cloud functions, firestore, expressjs. Để dễ dàng tìm hiểu thì ta cần có một ít kiến thức về ExpressJs. Demo app của chúng ta gồm các chức năng CRUD cơ bản. Nào Les't goo.

1. Setting up firebase

Đầu tiên ta cần phải cài Firebase CLI:

npm install -g firebase-tools

Sau khi cài đặt thành công, ta đăng nhập vào Firebase console để tạo project. Sau khi tạo project thành công ta tiếp tục tạo Cloud firestore. Ta di chuyển tới firestore option ở thanh công cụ bên trái, sau đó click vào Create database. Chúng ta sẽ sử dụng production option mode cho demo này.

2. Viết cloud function đầu tiên

Đầu tiên chúng ta mở terminal và login vào tài khoản firebase bằng command:

firebase login

Sau khi chạy command trên thì nó sẽ đưa ta đi trến trang xác thực ở trình duyệt. Sau khi xác thực thành công ta sẽ tạo 1 demo app. Ta chạy command :

firebase init functions

Ta chọn option sử dụng existing project rồi chọn project đã tạo ở bước đầu tiên.
Tiếp đến chọn option Language: JS hoặc TS. Và cuối cùng là chọn chấp nhận để cài npm dependencies.
Sau khi tạo thành công ta sẽ thấy cấu trúc thư mục

├── .firebaserc
├── .gitignore
├── .firebase.json
└── functions
    ├── package.json
    ├── tsconfig.json
    ├── .gitignore
    └── index.js

Khi mở file index.js, ta sẽ thấy:

const functions = require("firebase-functions");
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
// export const helloWorld = functions.https.onRequest((request, response) => {
//   functions.logger.info("Hello logs!", {structuredData: true});
//   response.send("Hello from Firebase!");
// });

Uncomment helloWord function ta sẽ được cloud function đầu tiên.

const functions = require("firebase-functions");

export const helloWorld = functions.https.onRequest((request, response) => {
  functions.logger.info("Hello logs!", {structuredData: true});
  response.send("Hello from Firebase!");
});

Để chạy cloud functions ở local ta chạy command:

npm run serve

Mở Url ở temirnal (ở đây là : http://localhost:5001/fir-app-70aa4/us-central1/helloWorld). Trên trình duyệt ta sẽ nhận được response : Hello from Firebase!

3. Kết hợp Express để xây dựng REST API

Cài đặt Express

npm i -s express

Sau khi cài đặt xong ta mở file index.js và tiến hành thiết lập cơ bản.

const functions = require("firebase-functions");
const express = require("express");

const app = express();
app.get("/", (req, res) => res.status(200).send("Hey there!"));
exports.app = functions.https.onRequest(app);

Sau khi chạy lại functions ta được: Ta mở url ở terminal: (http://localhost:5001/fir-app-70aa4/us-central1/app) sẽ nhận được response tương ứng là Hey there!

3.1 Tạo account service cho app

Để truy cập vào Firestore và admin tool từ app, ta cần phải tạo 1 service account. Ta click vào Project Overview ở thanh bên trái. Chuyển qua tab Service accounts chọn Nodejs và Generate new private key Chúng ta sẽ có 1 file JSON dạng :

{
  "type": "service_account",
  "project_id": "journal-rest-api",
  "private_key_id": "private_key_id",
  "private_key": "private_key",
  "client_email": "client_email",
  "client_id": "client_id",
  "auth_uri": "auth_url",
  "token_uri": "token_url",
  "auth_provider_x509_cert_url": "auth_provider_x509_cert_url",
  "client_x509_cert_url": "client_x509_cert_url"
}

3.2 Cấu hình firebase admin.

└── functions
      └── config
           ├── firebase.js
           ├── serviceAccountKey.json

serviceAccountKey.json đây là file ta vừa tải ở bước trên, để làm nhanh thì mình import vào dùng trực tiếp mà không cho vào .env. ✌️
Trong file firebase.js

const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `https://${serviceAccount.project_id}.firebaseio.com`,
});

const db = admin.firestore();

module.exports = {admin, db};

3.3 Xây dựng controller để nhận http request, thao tác với firestore

  • Add entry controller
└── functions
      └── controller
           ├── addEntry.js

Trong file addEntry.js: Nhận payload từ request body để lưu vàofirestore

const {db} = require('../config/firebase');
module.exports.addEntry = async (req, res) => {
  const {title, text} = req.body;
  try {
    const entry = db.collection('entries').doc();
    const entryObject = {
      id: entry.id,
      title,
      text,
    };

    entry.set(entryObject);

    res.status(200).send({
      status: 'success',
      message: 'entry added successfully',
      data: entryObject,
    });
  } catch (error) {
    res.status(500).json(error.message);
  }
}

Ở fileindex.js ta tiến hành tạo APIadd-entry

const functions = require('firebase-functions');
const express = require('express');
const {addEntry} = require('./controllers/addEntry');

const app = express();
app.get('/', (req, res) => res.status(200).send('Hey there!'));

app.post('/entries', addEntry);
exports.app = functions.https.onRequest(app);

Tiếp theo là test thử thành quả nào
Ở đây mình dùng THUNDER CLIENT extension để gửi request :
API POST: http://localhost:5001/fir-app-70aa4/us-central1/app/entries Body:

{
  "title": "My first entry",
  "text": "Hey there! I'm awesome!"
}

Sau khi gửi ta nhận được phản hồi: entry added successfull Kiểm tra trong firestore: Như vậy là ta đã add thành công rồi.

  • Get entry controller
└── functions
      └── controller
           ├── addEntry.js
           ├── getEntry.js

getEntry.js

const {db} = require('../config/firebase');

module.exports.getAllEntries = async (req, res) => {
  try {
    const allEntries = [];
    const querySnapshot = await db.collection('entries').get();

    querySnapshot.forEach( (doc) => allEntries.push(doc.data()));

    return res.status(200).json(allEntries);
  } catch (error) {
    return res.status(500).json(error.message);
  }
};

Ta thêm API getAllEntries vào file index.js

app.get('/entries', getAllEntries);

Kết quả:

  • Delete entry controller deleteEntry.js
const {db} = require('../config/firebase');

module.exports.deleteEntry = async (req, res) =>{
  const {entryId} = req.params;

  try {
    const entry = db.collection('entries').doc(entryId);

    await entry.delete().catch((error) => {
      return res.status(400).json({
        status: 'error',
        message: error.message,
      });
    });

    return res.status(200).json({
      status: 'success',
      message: 'entry deleted successfully',
    });
  } catch (error) {
    return res.status(500).json(error.message);
  }
};

Thêm API delete entry vào fìle index.js

app.delete('/entries/:entryId', deleteEntry);

  • Update entry controller updateEntry.js
const {db} = require('../config/firebase');


module.exports.updateEntry = async (req, res) => {
  const {body: {text, title}, params: {entryId}} = req;
  try {
    const entry = db.collection('entries').doc(entryId);
    const currentData = (await entry.get()).data() || {};
    const entryObject = {
      title: title || currentData.title,
      text: text || currentData.text,
    };

    await entry.set(entryObject).catch((error) => {
      return res.status(400).json({
        status: 'error',
        message: error.message,
      });
    });

    return res.status(200).json({
      status: 'success',
      message: 'entry updated successfully',
      data: entryObject,
    });
  } catch (error) {
    return res.status(500).json(error.message);
  }
};

Thêm API update vào file index.js:

app.patch('/entries/:entryId', updateEntry);

Kết quả

KẾT

Bài viết này hi vọng sẽ giúp các bạn build một REST API với các chức năng đơn giản sử dụng cloud functions kết hợp với expressJS và firestore một cách nhanh nhất.
Xin chào và hẹn gặp lại !

Tài liệu tham khảo :

Source: https://viblo.asia/p/xay-dung-rest-api-voi-firebase-cloud-functions-firestore-va-expressjs-maGK7G0bKj2