Parse Cloud Code 章節

預設來說,Parse Cloud 環境入口為 ./cloud/main.js,路徑可以透過 parse server options 設定

Cloud Functions

  • Linkopen in new window Cloud Function 定義由 Parse.Cloud.define 處理,因為是在 Parse 環境下,所以可以直接調用 Parse 相關功能,比如下面範例

創建 Cloud Code Function

Parse.Cloud.define('averageStars', async (request) => {
  const query = new Parse.Query('Review');
  query.equalTo('movie', request.params.movie);
  const results = await query.find();
  let sum = 0;
  for (let i = 0; i < results.length; ++i) {
    sum += results[i].get("stars");
  }
  return sum / results.length;
});

執行 Cloud Code Function

const params =  { movie: "The Matrix" };
const ratings = await Parse.Cloud.run("averageStars", params);

Request 物件

  • params: 傳進 function 的參數
  • user: 當前調用的 User
  • master: 是否透過 masterKey 調用

限制條件

限制傳入參數必須有 movie,並且只有登入用戶能調用此 function

Parse.Cloud.define("averageStars", async (request) => {
  // ...same above
},{
  fields : ['movie'],
  requireUser: true
});

Parse.Cloud.define("averageStars", async (request) => {
  const query = new Parse.Query("Review");
  query.equalTo("movie", request.params.movie);
  const results = await query.find();
  // ...
  return sum / results.length;
},{
  fields : {
    movie : {
      required: true,
      type: String,
      options: val => {
        return val.length < 20;
      },
      error: "Movie must be less than 20 characters"
    }
  },
  requireUserKeys: {
    accType : {
      options: 'reviewer',
      error: 'Only reviewers can get average stars'
    }
  }
});

常見 options

  • Linkopen in new window
  • requireMaster
  • requireUser
  • validateMasterKey
  • fields
  • requireAnyUserRoles
  • requireAllUserRoles
  • requireUserKeys

更多限制方式可參考這邊open in new window

Validation 函數檢驗

當一般 options 無法滿足你的檢驗需求時,你可以傳入一個 function 對其進行更詳細的檢驗,也提升檢驗邏輯的複用能力

const validationRules = request => {
  if (request.master) {
    return;
  }
  if (!request.user || request.user.id !== 'masterUser') {
    throw 'Unauthorized';
  }
}

Parse.Cloud.define('adminFunction', request => {
  // do admin code here, confident that request.user.id is masterUser, or masterKey is provided
}, validationRules)

Parse.Cloud.define('adminFunctionTwo', request => {
  // do admin code here, confident that request.user.id is masterUser, or masterKey is provided
}, validationRules)
  • validation 函數會在 Cloud Code Function 前執行,可以使用 async 或 promise 型態的檢驗函數,但盡量確保檢驗過程的簡短,讓 Cloud Code Function 能更快被執行

Cloud Jobs

有時您想執行長時間運行的函數,並且不想等待回應。Cloud Jobs 就是為此而生的。

創建 Job

Parse.Cloud.job("myJob", (request) =>  {
  // params: 傳入參數
  // headers: 觸發 job 的請求 headers
  // log: 傳入 request 的 logger
  // message: 更新 job 狀態的函數
  const { params, headers, log, message } = request;
  message("I just started");
  return doSomethingVeryLong(request);
});

執行 Job

執行 Job 必須以 master 權限進行,注意 url 結構是以綁定的 parse server 位置中的

  • /[parse-mount-path]/jobs/[job-name]
curl -X POST -H 'X-Parse-Application-Id: appId' -H 'X-Parse-Master-Key: masterKey' https://my-parse-server.com/parse/jobs/myJob

查看 Job

在 Parse Dashboard 中能夠查看,或是使用 masterKey_JobStatus class 進行 query

Save Triggers

  • Linkopen in new window 當我們想對資料格式做些特殊處理時,如果每一次都要單獨寫一遍非常無意義,此時可以使用 save triggers 對資料的寫入前、寫入後做特定的處理

validation

以下範例在寫入評價前檢查 stars 數量是否 valid

Parse.Cloud.beforeSave('Review', (request) => {
  // ...
}, {
  fields: {
    stars : {
      required:true,
      options: stars => {
        return stars >= 1 && stars =< 5;
      },
      error: 'Your review must be between one and five stars'
    }
  }
})

如果函數拋出異常,Review 對象將不會被保存,客戶端會報錯。如果沒有拋出任何東西,對象將被正常保存。

modifying

或是在資料儲存寫入前進行修改,以下範例確保存入的 comment 欄位長度在 140 字元內

Parse.Cloud.beforeSave("Review", (request) => {
  // original: 保存物件原本的值,若為新物件則為不存在
  // object: 即將保存的物件
  const { object, original } = request
  const comment = object.get("comment");
  if (comment.length > 140) {
    // Truncate and add a ...
    object.set("comment", comment.substring(0, 137) + "...");
  }
});

predefined class

對於 Parse 預定義的內建 class,請直接傳入 Parse.User 這種方式,而不是字串

Parse.Cloud.beforeSave(Parse.User, async (request) => {
  // code here
},
  // Validation Object or Validation Function
)

afterSave

前面都是在儲存前做事情,我們也可以使用 afterSave 在物件存入後進行操作,通常用於較為冗長的操作,不希望此操作影響到物件儲存的情況下可以考慮使用,例如下面範例在 Comment 物件存入後,對所屬的 Post 物件 comment 欄位加值

Parse.Cloud.afterSave("Comment", (request) => {
  const query = new Parse.Query("Post");
  query.get(request.object.get("post").id)
    .then(function(post) {
      post.increment("comments");
      return post.save();
    })
    .catch(function(error) {
      console.error("Got an error " + error.code + " : " + error.message);
    });
});

上面的動作實際上在完成前就會先返回使用者,即使在 post.save() 時發生錯誤,用戶也不會被通知,錯誤可以在 Cloud Code Log 中看到,為了在 afterSave 處理程序完成之前回應客戶端,您的處理程序可能不可返回 promise,並且不要使用 async/await。

Context

context 是一個讓開發者能在不同時機使用的物件空間,context 會從 beforeSave 處理程序傳遞到 afterSave 處理程序。

Delete Triggers

  • Linkopen in new window 在刪除物件之前運行自定義 Cloud Code。您可以使用 beforeDelete 方法執行此操作。

beforeDelete

以下範例在刪除 Album 物件之前,檢查其中是否還有 photos 存在,當錯誤拋出時,album 將不會被誤刪除

Parse.Cloud.beforeDelete("Album", async ({ object }) => {
  const query = new Parse.Query("Photo");
  query.equalTo("album", object);
  const count = await query.count({useMasterKey:true})
  if (count > 0) {
    throw "Can't delete album if it still has photos.";
  }
});

afterDelete

以下範例在刪除 Post 後,需要一次將 post 的 Comment 全部刪除

Parse.Cloud.afterDelete("Post", ({ object }) => {
  const query = new Parse.Query("Comment");
  query.equalTo("post", object);
  // 這邊不使用 async/await 可以加快回應使用者的時間,此操作不影響使用者後續動作
  query.find()
    .then(Parse.Object.destroyAll)
    .catch((error) => {
      console.error("Error finding related comments " + error.code + ": " + error.message);
    });
});

Find Triggers

  • Linkopen in new window 在某些情況下,可能希望轉換傳入查詢、添加額外或增加默認限制

beforeFind or afterFind

// Properties available
Parse.Cloud.beforeFind('MyObject', (req) => {
  let query = req.query; // the Parse.Query
  let user = req.user; // the user
  let triggerName = req.triggerName; // beforeFind
  let isMaster = req.master; // if the query is run with masterKey
  let isCount = req.count; // if the query is a count operation
  let logger = req.log; // the logger
  let installationId = req.installationId; // The installationId
});
// Returning a different query
Parse.Cloud.beforeFind('MyObject', (req) => {
  let query = req.query;
  let otherQuery = new Parse.Query('MyObject');
  otherQuery.equalTo('key', 'value');
  return Parse.Query.or(query, otherQuery);
});

Security

要覆蓋對象和類訪問權限,您可以設置 useMasterKey: true 如果請求接受主密鑰選項,但需要注意,使用 master 權限卉返回物件所有資源,在將其發送到客戶端之前,您可能希望刪除客戶端不應訪問的物件屬性。

query.find({ useMasterKey: true });

Config

默認情況下,Parse Config 參數可以公開讀取,如果參數包含不應向客戶端公開的敏感信息,則可能不希望這樣做

// 藉由添加 requireMasterKey 在 Config 欄位,可以添加 master 權限的 config 設定
const config = await Parse.Config.get({useMasterKey: true});
const privateParam = config.get("privateParam");
Last Updated:
Contributors: johnnywang