Moralis 云函數(shù)

2023-05-10 14:27 更新

定義云函數(shù)

對(duì)于復(fù)雜的應(yīng)用程序,有時(shí)您需要一些不在移動(dòng)設(shè)備上運(yùn)行的邏輯。 ?Cloud Code? 使這成為可能。

?Cloud Code? 易于使用,因?yàn)樗⒃谥С謹(jǐn)?shù)千個(gè)應(yīng)用程序的同一個(gè) ?Moralis JavaScript SDK? 之上。 唯一的區(qū)別是此代碼在您的 ?Moralis Dapp? 中運(yùn)行,而不是在用戶的移動(dòng)設(shè)備上運(yùn)行。 當(dāng)您更新您的云代碼時(shí),它會(huì)立即可供所有移動(dòng)環(huán)境使用。 您不必等待應(yīng)用程序的新版本。 這使您可以即時(shí)更改應(yīng)用程序行為并更快地添加新功能。

即使您只熟悉移動(dòng)開(kāi)發(fā),我們也希望您會(huì)發(fā)現(xiàn) ?Cloud Code? 簡(jiǎn)單易用。

您可以直接在儀表板上編輯云代碼或設(shè)置 IDE。

spaces_-MVStbACGLCycg7J5WQ2_uploads_git-blob-39cb7ed6dc5927c2c657af390873c6f857d11f90_Screenshot 2022-04-08 at 2

spaces_-MVStbACGLCycg7J5WQ2_uploads_git-blob-c2cb234a2f746c35d0b083b2209a544e80c5c029_Moralis_dashboard_cloudfunction

讓我們看一個(gè)稍微復(fù)雜一點(diǎn)的例子,其中 ?Cloud Code? 很有用。 在云中進(jìn)行計(jì)算的一個(gè)原因是,如果您只需要一點(diǎn)點(diǎn)信息,就不必將大量對(duì)象列表發(fā)送到設(shè)備。

例如,假設(shè)您正在編寫(xiě)一個(gè)讓人們?cè)u(píng)論電影的應(yīng)用程序。 單個(gè) ?Review ?對(duì)象可能如下所示:

{
  "movie": "The Matrix",
  "stars": 5,
  "comment": "Too bad they never made any sequels."
}

如果您想查找 The Matrix 的平均星級(jí)數(shù),您可以查詢所有評(píng)論以及設(shè)備上的平均星級(jí)數(shù)。 但是,當(dāng)您只需要一個(gè)號(hào)碼時(shí),這會(huì)占用大量帶寬。 使用 ?Cloud Code?,我們可以只傳遞電影的名稱,并返回平均星級(jí)。

?Cloud Functions? 接受請(qǐng)求對(duì)象上的 JSON 參數(shù)字典,因此我們可以使用它來(lái)傳遞電影名稱。 整個(gè) ?Moralis JavaScript SDK? 在云環(huán)境中可用,因此我們可以使用它來(lái)查詢 Review 對(duì)象。 實(shí)現(xiàn) averageStars 的代碼如下所示:

Moralis.Cloud.define("averageStars", async (request) => {
  const query = new Moralis.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;
});

使用 averageStars 和 hello 的唯一區(qū)別是我們必須在調(diào)用 ?Cloud Function? 時(shí)提供將在 ?request.params.movie? 中訪問(wèn)的參數(shù)。 

全局包

以下包在 ?Cloud Function? 代碼中全局可用,無(wú)需 ?require ?語(yǔ)句即可使用。

重要 - 不要?jiǎng)?chuàng)建任何全局變量

?Cloud Functions? 不能有狀態(tài)。 他們可以讀取數(shù)據(jù)并將數(shù)據(jù)寫(xiě)入數(shù)據(jù)庫(kù),但您不能像下面的示例中那樣創(chuàng)建全局變量。

let name = "Satoshi"; // NOT ALLOWED

Moralis.Cloud.define("functionName", async (request) => {
  let age = 20; // allowed
});

原因是您的云代碼將在您的服務(wù)器的許多實(shí)例之間實(shí)現(xiàn)負(fù)載平衡,以便 Moralis 可以無(wú)限擴(kuò)展您的應(yīng)用程序。

注意:服務(wù)器的不同實(shí)例不會(huì)共享在函數(shù)體之外定義的任何變量。

您的服務(wù)器的所有實(shí)例將共享同一個(gè)數(shù)據(jù)庫(kù)。 因此,如果您需要跨實(shí)例共享數(shù)據(jù),建議您將其存儲(chǔ)在數(shù)據(jù)庫(kù)中。

如果你創(chuàng)建全局變量,參考下面例子的結(jié)果

let count = 0; // very bad

Moralis.Cloud.define("increment", async (request) => {
  logger.info(count);
  count++;
});

// If you call the function above you may get the following results
// 0
// 0
// 0
// 1
// 1
// 2
// 1
// 3
// 0
// 2

為什么increment功能無(wú)法正常工作?

因?yàn)槊看握?qǐng)求被隨機(jī)路由到服務(wù)器的不同實(shí)例并且每個(gè)實(shí)例都有自己?jiǎn)为?dú)的計(jì)數(shù)變量。

因此,我們希望您現(xiàn)在明白為什么不應(yīng)該使用全局變量。但是全局常量可以使用,因?yàn)樗鼈冎粫?huì)被復(fù)制到所有實(shí)例并且不會(huì)改變。

IDE 設(shè)置

您可以使用?moralis-admin-cli? 在您喜歡的IDE 中編寫(xiě)您的云函數(shù)。

首先,您需要通過(guò)在終端中運(yùn)行以下代碼來(lái)安裝它:

npm install -g moralis-admin-cli

安裝 ?Moralis Admin CLI? 后,您可以前往管理面板并在您要使用的服務(wù)器上打開(kāi)云功能。

在模態(tài)框的下部,將有一個(gè)代碼片段,您需要在終端中運(yùn)行。

您唯一需要更改的是計(jì)算機(jī)上包含 ?Cloud Functions? 的本地 JavaScript 文件夾的路徑。

moralis-admin-cli watch-cloud-folder --moralisApiKey your_api_key --moralisApiSecret your_api_secret --moralisSubdomain subdomain.moralis.io --autoSave 1 --moralisCloudfolder /path/to/cloud/folder

運(yùn)行命令后,每次保存都會(huì)在后端自動(dòng)更新云代碼!

調(diào)試

出于調(diào)試或信息目的,打印消息通常很有用。 為此目的可以獲得一個(gè)記錄器。 它會(huì)將消息打印到 Moralis 儀表板的“Logs > info”部分。

const logger = Moralis.Cloud.getLogger();
logger.info("Hello World"); 

在控制臺(tái)中實(shí)時(shí)打印日志

moralis-admin-cli get-logs --moralisApiKey MORALIS_CLI_API_KEY --moralisApiSecret MORALIS_CLI_SECRET_KEY

調(diào)用云函數(shù)

你可以通過(guò)?JS?、?React?來(lái)實(shí)現(xiàn)

const params =  { movie: "The Matrix" };
const ratings = await Moralis.Cloud.run("averageStars", params);
// ratings should be 4.5
import { useMoralisCloudFunction } from "react-moralis";

function App() {
    const { fetch } = useMoralisCloudFunction(
        "averageStars",
        { movie: "The Moralis" },
        { autoFetch: false }
    );

    const cloudCall = () => {
        fetch({
            onSuccess: (data) => console.log(data), // ratings should be 4.5
        });
    };

    return (
        <button onClick={cloudCall}>Make Cloud Call</button>
    );
}

export default App;

通常,會(huì)傳遞兩個(gè)參數(shù)給 Cloud Functions:

  1. ?request ?- 請(qǐng)求對(duì)象包含有關(guān)請(qǐng)求的信息。 設(shè)置了以下字段:
  2. ?params ?- 參數(shù)對(duì)象由客戶端發(fā)送到函數(shù)。
  3. ?user ?- 發(fā)出請(qǐng)求的 ?Moralis.User?。 如果沒(méi)有登錄用戶,則不會(huì)設(shè)置。

如果函數(shù)成功,客戶端中的響應(yīng)如下所示:

{ "result": 4.8 }

如果出現(xiàn)錯(cuò)誤,客戶端中的響應(yīng)如下所示:

{
  "code": 141,
  "error": "movie lookup failed"
}

通過(guò) REST API 調(diào)用

可以使用簡(jiǎn)單的 GET 請(qǐng)求直接調(diào)用 ?Cloud Functions?。 將 Moralis 應(yīng)用程序 ID 和任何云函數(shù)參數(shù)作為查詢參數(shù)添加到 Moralis 服務(wù)器 URL。 假設(shè)您有以下云功能:

Moralis.Cloud.define("Hello", (request) => {
return `Hello ${request.params.name}! Cloud functions are cool!`
});

然后 URL 將如下所示:

https://1a2b3c4c5d6f.moralis.io:2053/server/functions/Hello?_ApplicationId=1a2b3c4c5d6f1a2b3c4c5d6f&name=CryptoChad

URL 具有以下結(jié)構(gòu):

  • 完整的Morlis server地址
  • /functions/
  • Cloud Function名稱
  • ??_ApplicationId=yourMoralisAppId
  • (可選) Cloud Function 參數(shù)鍵值對(duì): &m1=value&m2=value.

云代碼中的萬(wàn)能鑰匙

在需要主密鑰的請(qǐng)求中設(shè)置 ?useMasterKey:true?。

示例:

query.find({useMasterKey:true});
object.save(null,{useMasterKey:true});
Moralis.Object.saveAll(objects,{useMasterKey:true});

注意:當(dāng)您使用 ?useMasterKey:true? 時(shí),默認(rèn)情況下可以在云功能中訪問(wèn)主密鑰

重要提示:不應(yīng)在您的前端代碼上使用主密鑰,因?yàn)樗梢栽谟脩舻臑g覽器中訪問(wèn)。

如果您使用來(lái)自您控制的另一個(gè)后端服務(wù)器的主密鑰,您可以使用以下代碼來(lái)初始化主密鑰:

const Moralis = require("moralis/node"); // Node.js
const appId = "YOUR_MORALIS_APP_ID";
const serverUrl = "YOUR_MORALIS_SERVER_URL";
const masterKey = "YOUR_MORALIS_MASTER_KEY"; 

Moralis.start({ serverUrl, appId, masterKey });

云功能驗(yàn)證

確保提供 ?Cloud Function? 所需的參數(shù)并采用必要的格式非常重要。 您可以指定將在您的云函數(shù)之前調(diào)用的驗(yàn)證器函數(shù)或?qū)ο蟆?/p>

讓我們看一下averageStars的例子。 如果你想確保 ?request.params.movie? 被提供,并且 averageStars 只能由登錄用戶調(diào)用,你可以在函數(shù)中添加一個(gè)驗(yàn)證器對(duì)象。

Moralis.Cloud.define("averageStars", async (request) => {
  const query = new Moralis.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;
},{
  fields : ['movie'],
  requireUser: true
});

如果不滿足驗(yàn)證器對(duì)象中指定的規(guī)則,云函數(shù)將不會(huì)運(yùn)行。 這意味著您可以自信地構(gòu)建您的函數(shù),知道 ?request.params.movie? 以及 ?request.user? 已定義。

高級(jí)云功能驗(yàn)證

通常,不僅定義 ?request.params.movie? 很重要,而且它是正確的數(shù)據(jù)類型。 您可以通過(guò)為“驗(yàn)證器”中的字段參數(shù)提供一個(gè)對(duì)象來(lái)做到這一點(diǎn)。

Moralis.Cloud.define("averageStars", async (request) => {
  const query = new Moralis.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;
},{
  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'
    }
  }
});

此功能僅在以下情況下運(yùn)行:

  • ?request.params.movie? 已定義。
  • ?request.params.movie? 是一個(gè)字符串。
  • ?request.params.movie? 少于 20 個(gè)字符。
  • ?request.user? 已定義。
  • ?request.user.get('accType')? 已定義。
  • ?request.user.get('accType')? 等于'reviewer'。

完整的內(nèi)置驗(yàn)證選項(xiàng)包括:

  • ?requireMaster?:函數(shù)是否需要?masterKey?才能運(yùn)行。
  • ?requireUser?:函數(shù)是否需要 ?request.user? 才能運(yùn)行。
  • ?validateMasterKey?:驗(yàn)證器是否應(yīng)該在 ?masterKey ?上運(yùn)行(默認(rèn)為 ?false?)。
  • ?fields?:請(qǐng)求所需的字段的數(shù)組或?qū)ο蟆?/li>
  • ?requireUserKeys?:要在 ?request.user? 上驗(yàn)證的字段數(shù)組。

?.fields? 上的全部?jī)?nèi)置驗(yàn)證選項(xiàng)包括:

  • ?type?:?request.params[field]? 或 ?request.object.get(field)? 的類型。
  • ?default?:如果該字段為空,則該字段應(yīng)默認(rèn)為什么。
  • ?required?:該字段是否為必填項(xiàng)。
  • ?options?:?jiǎn)蝹€(gè)選項(xiàng)、選項(xiàng)數(shù)組或字段允許值的自定義函數(shù)。
  • ?constant?:字段是否不可變。
  • ?error?:驗(yàn)證失敗時(shí)的自定義錯(cuò)誤消息。

您還可以將函數(shù)傳遞給驗(yàn)證器。 這可以幫助您將重復(fù)出現(xiàn)的邏輯應(yīng)用于您的云代碼。

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

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

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

需要注意的一些注意事項(xiàng)

驗(yàn)證功能將在您的 ?Cloud Code Functions? 之前運(yùn)行。 您可以在此處使用 ?async ?和 ?Promise?,但盡量保持驗(yàn)證盡可能簡(jiǎn)單和快速,以便您的云請(qǐng)求快速解決。

如前所述,云驗(yàn)證器對(duì)象不會(huì)驗(yàn)證是否提供了主密鑰,除非設(shè)置了 ?validateMasterKey:true?。 但是,如果您將驗(yàn)證器設(shè)置為函數(shù),則該函數(shù)將始終運(yùn)行。

單位

Moralis 單位在您的云函數(shù)中可用。

為了成功運(yùn)行 units 函數(shù),您始終需要指定一個(gè)方法和一個(gè)值

轉(zhuǎn)換wei

將任何以太幣值轉(zhuǎn)換為 wei。

const result = await Moralis.Cloud.units({
  method: "toWei",
  value: 1
});
return result;

結(jié)果為: 1000000000000000000

將wei轉(zhuǎn)換

將任何wei值轉(zhuǎn)換為ether。

const result = Moralis.Cloud.units({
  method: "fromWei",
  value: 1000000000000000
});
return result;

結(jié)果為: 0.001

十六進(jìn)制

將任何給定值轉(zhuǎn)換為其十六進(jìn)制表示。

 const result = Moralis.Cloud.units({
   method: "toHex",
   value: 100
 });
 return result;

結(jié)果為: 64

使用小數(shù)

使用自定義小數(shù)值轉(zhuǎn)換任何給定值。

result = Moralis.Cloud.units({
  method: "fromWei",
  value: 10000000000000,
  decimals: 10
});
return result

結(jié)果為: 1000

Web3

Cloud Code 中提供了 Web3 功能,包括調(diào)用合約方法的能力。 Moralis 使用 Web3.js 和 ethers.js 庫(kù)。

// get a web3 instance for a specific chain
const web3 = Moralis.web3ByChain("0x1"); // mainnet
    
// get an ethers instance for a specific chain and ethersjs library
const web3 = Moralis.ethersByChain("0x4"); // rinkeby

當(dāng)您調(diào)用 ?Moralis.ethersByChain()? 時(shí),您將獲得一個(gè)包含?provider?和 ?ethers ?庫(kù)的對(duì)象。

{
  provider: //A provider with the supplied chainId,
  ethers: //ethers.js library,
}

通過(guò)為您希望連接的區(qū)塊鏈提供 ?chainId ?來(lái)請(qǐng)求 web3 對(duì)象。

注意: ?Moralis.web3ByChain()? 或 ?Moralis.ethersByChain()? 返回的 web3 實(shí)例無(wú)法簽署交易。 有一種使用私鑰簽署交易的方法,但出于安全原因不建議這樣做。

以下是當(dāng)前支持的鏈列表。

 Chain名稱  ChainId
 Ethereum (Mainnet)  ?0x1?
 Ropsten (Ethereum Testnet)  ?0x3?
 Rinkeby  ?0x4?
 Goerli (Ethereum Testnet)  ?0x5?
 Kovan  ?0x2a?
 Binance Smart Chain (Mainnet)  ?0x38?
 Binance Smart Chain (Testnet)  ?0x61?
 Matic (Mainnet)  ?0x89?
 Mumbai (Matic Testnet)  ?0x13881?
 Local Dev (Ganache, Hardhat)  ?0x539?

合同

一旦你有了一個(gè) web3 實(shí)例,你就可以通過(guò)使用 ?ABI ?和合約地址構(gòu)造一個(gè)合約實(shí)例來(lái)使用它來(lái)進(jìn)行合約調(diào)用。

const contract = new web3.eth.Contract(abi, address);

為方便起見(jiàn),Moralis 為 ERC20、ERC721 和 ERC1155 捆綁了 Openzepplin ABI。

  • ?Moralis.Web3.abis.erc20 ?
  • ?Moralis.Web3.abis.erc721 ?
  • ?Moralis.Web3.abis.erc1155?

把這一切放在一起...

const web3 = Moralis.web3ByChain("0x38"); // BSC
const abi = Moralis.Web3.abis.erc20;
const address = "0x...."

// create contract instance
const contract = new web3.eth.Contract(abi, address);

// get contract name
const name = await contract.methods
  .name()
  .call()
  .catch(() => "");

有關(guān) Web3.js 合約接口的更多詳細(xì)信息,請(qǐng)參閱 Web3.js 文檔的 web3.eth.Contract 部分。

?Moralis.web3ByChain()? 返回的 Web3 實(shí)例無(wú)法簽署交易。 在不久的將來(lái),可以使用自定義插件來(lái)做到這一點(diǎn)。 目前,如果您需要進(jìn)行鏈上合約交互,請(qǐng)考慮在前端執(zhí)行它們或創(chuàng)建一個(gè) NodeJS 后端,您可以在其中訪問(wèn)Truffle's HdWalletProvider。

合同 ABI

要查找已在以太坊主網(wǎng)上發(fā)布的合約的 ?ABI?,您可以通過(guò)搜索合約地址并查看“合約”選項(xiàng)卡來(lái)查看 Etherscan。 發(fā)布 ABI 的其他鏈也有類似的區(qū)塊瀏覽器。 例如,你可以去 BscScan 獲取 ?Binance Smart Chain?。

對(duì)于你自己的合約,?ABI ?可以在編譯合約后的 build 目錄中找到

  • Truffle: ?/truffle/build/contracts/myContract.json
  • Hardhat: ?/artifacts/contracts/myContract.sol/myContract.json?

如何使用自定義 RPC url 的示例

通過(guò)使用?ethers?:

const web3 = Moralis.ethersByChain("0x1")
var url = 'https://speedy-nodes-nyc.moralis.io/YOUR_ID_HERE/eth/mainnet';
var customHttpProvider = new web3.ethers.providers.JsonRpcProvider(url);
customHttpProvider.getBlockNumber().then((result) => {
    logger.info("Current block number: " + result);
});

通過(guò)使用web3:

Moralis.Cloud.define("run_contract_function_with_web3", async (request) => {

  web3 = new Moralis.Web3(new Moralis.Web3.providers.HttpProvider("https://speedy-nodes-nyc.moralis.io/YOUR_ID_HERE/bsc/mainnet"));
    const abi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]
    address = "0x2170Ed0880ac9A755fd29B2688956BD959F933F8"
    const contract = new web3.eth.Contract(abi, address)
    const name = await contract.methods
      .name()
      .call()
      .catch((e) => logger.error(`callName: ${e}${JSON.stringify(e, null, 2)}`))
    return name;    
});

IPFS

IPFS 功能在您的云功能中可用。 為了成功上傳到 IPFS,您需要指定:

  • A source type:?sourceType?
  • A source:?source?

以下是 ?sourceType ?支持的值

url

將給定 URL 的內(nèi)容推送到 IPFS。

const result = await Moralis.Cloud.toIpfs({
  sourceType: "url",
  source: "https://moralis.io/wp-content/uploads/2021/06/Moralis-Glass-Favicon.svg",
});
return result;

結(jié)果為:{ ?"path": "https://ipfs.moralis.io:2053/ipfs/QmYrUVhr1f6ZpZ4jrmi7mSv5X8MGjxxrgaERWde3cFASL6"? }

string

將字符串推送到 IPFS。

 const result = await Moralis.Cloud.toIpfs({
   sourceType: "string",
   source: "Moralis rules <3",
 });
 return result;

結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmeYY26fCN4t2Apo9Nqix5ZDhJwcjoyDVLLz85TLkoiqpn"? }

object

將對(duì)象推送到 IPFS。

const result = await Moralis.Cloud.toIpfs({
  sourceType: 'object',
  source: {
    type: "Monster",
    lp: 100,
    spells: {
      base: ["spell one","spell two"],
      locked: ["spell three"],
    }
  },
});
return result;

結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmWowsJ74rYCHUYhag83Puky1qZTSsdj3n7bT2ejE2NvCJ"? }

Base64 Binary

將 base64 文件推送到 IPFS。

const result = await Moralis.Cloud.toIpfs({
  sourceType: "base64Binary",
  source: "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoGCBETExcTEhETGBcYFxkaGBkZGRkZG",
});
return result;

結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmaZRSn8cHKUN5LsvuY6M8a5LzV76uFKeZ9khthPj2rHhw" ?}

Base64

將 base64 字符串推送到 IPFS。

const result = await Moralis.Cloud.toIpfs({
  sourceType: "base64",
  source: "TW9yYWxpcyBydWxlcyA8Mw=="
});
return result;

結(jié)果為: { ?"path": "https://ipfs.moralis.io:2053/ipfs/QmeYY26fCN4t2Apo9Nqix5ZDhJwcjoyDVLLz85TLkoiqpn"? }


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)