アプリケーションのコーディング
プロジェクトのルートディレクトリに「index.js」ファイルを作成済みです。このファイルにはアプリケーションのバックエンドロジックが含まれます。
プロジェクトのルートディレクトリにフォルダを作成し、「public」と名付けます。このフォルダにはフロントエンドロジックのファイルが含まれます。publicフォルダ(Alien City/public/)内に以下のファイルを作成してください:
- index.html:アプリケーションのフロントエンドのHTMLコードを含むファイルです。
- main.js:フロントエンドとバックエンドを接続するJavaScriptコードを含むファイルです。
以下は、Alien Cityプロジェクトの最終的なフォルダ構造です。

index.js、index.html、およびmain.jsファイルをコーディングします。また、app-config.jsonファイルも更新します。
Note: このセクションのコードを確認し、内容を十分に理解してください。
以下のコードをコピーし、IDEを使用してプロジェクトの対応するファイルに貼り付けて保存してください。
index.js
copy
var express = require('express');
var app = express();
var catalyst = require('zcatalyst-sdk-node');
app.use(express.json());
app.use(express.static('public'));
const tableName = 'AlienCity'; // Data Storeに作成したテーブル
const columnName = 'CityName'; // テーブルに作成したカラム
app.post('/alien', (req, res) => {
var cityJson = req.body;
console.log(req.body)
var catalystApp = catalyst.initialize(req);
getDataFromCatalystDataStore(catalystApp, cityJson.city_name).then(cityDetails => {
if (cityDetails.length == 0) {
console.log("Alien alert!");
var rowData = {}
rowData[columnName] = cityJson.city_name;
var rowArr = [];
rowArr.push(rowData);
// Catalyst Data Storeテーブルに都市名を行として挿入する
catalystApp.datastore().table(tableName).insertRows(rowArr).then(cityInsertResp => {
res.send({
"message": "Thanks for reporting!"
});
}).catch(err => {
console.log(err);
sendErrorResponse(res);
})
} else {
res.send({
"message": "Looks like you are not the first person to encounter aliens in this city! Someone has already reported an alien encounter here!"
});
}
}).catch(err => {
console.log(err);
sendErrorResponse(res);
})
});
app.get('/alien', (req, res) => {
var city = req.query.city_name;
// Catalyst SDKを初期化する
var catalystApp = catalyst.initialize(req);
getDataFromCatalystDataStore(catalystApp, city).then(cityDetails => {
if (cityDetails.length == 0) {
res.send({
"message": "Hurray! No alien encounters in this city yet!",
"signal": "negative"
});
} else {
res.send({
"message": "Uh oh! Looks like there are aliens in this city!",
"signal": "positive"
});
}
}).catch(err => {
console.log(err);
sendErrorResponse(res);
})
});
function getDataFromCatalystDataStore(catalystApp, cityName) {
return new Promise((resolve, reject) => {
// Catalyst Data Storeテーブルにクエリを実行する
catalystApp.zcql().executeZCQLQuery("Select * from " + tableName + " where " + columnName + "='" + cityName + "'").then(queryResponse => {
resolve(queryResponse);
}).catch(err => {
reject(err);
})
});
}
function sendErrorResponse(res) {
res.status(500);
res.send({
"error": "Internal server error occurred. Please try again in some time."
});
}
app.listen(process.env.X_ZOHO_CATALYST_LISTEN_PORT || 9000, () => {
})
module.exports = app;
index.html
copy
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AlientCityAppClient</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
</script>
<script src="main.js"> </script>
</head>
<body>
<br>
<br>
<center>
<h1>ALIEN CITY</h1>
</center>
<div class="container">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab"
aria-controls="check" aria-selected="true">Check My City</a>
</li>
<li class="nav-item">
<a class="nav-link" id="report-tab" data-toggle="tab" href="#report" role="tab" aria-controls="report"
aria-selected="false">Report Alien Encounter</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab">
<br>
<br>
<form>
<div class="form-group">
<label for="city-get-input"> <b>Check if your city has aliens:</b> </label>
<input type="text" class="form-control" id="city-get-input" aria-describedby="checkCity"
placeholder="Enter City Name">
</div>
<button type="submit" class="btn btn-primary"
onclick="getAlienEncounter();return false;">Check</button>
</form>
<br>
<br>
<div id="result-container">
<div id="result-text">
</div>
<br>
<div id="result-image">
</div>
</div>
<div id="loader" style="display: none;">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
<div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab">
<br>
<br>
<form>
<div class="form-group">
<div class="city-post-input">
<label for="exampleInputEmail1"> <b>Enter the name of the city where you encountered an alien:</b> </label>
<input type="text" class="form-control" id="city-post-input" aria-describedby="cityPost"
placeholder="Enter City Name">
</div>
</div>
<button type="submit" class="btn btn-primary"
onclick="postAlienEncounter();return false;">Report</button>
</form>
</div>
</div>
</div>
</body>
</html>
main.js
copy
function postAlienEncounter() {
debugger;
var city = $("#city-post-input").val();
$.ajax({
url: "/alien",
type: "post",
contentType: "application/json",
data: JSON.stringify({
"city_name": city
}),
success: function (data) {
alert(data.message);
},
error: function (error) {
alert(error.message);
}
});
}
function getAlienEncounter() {
showLoader();
var positive = "https://media.giphy.com/media/Y1GYiLui9NHcxVKhdo/giphy.gif";
var negative = "https://media.giphy.com/media/fsPcMdeXPxSP6zKxCA/giphy.gif";
var city = $("#city-get-input").val();
$.ajax({
url: "/alien?city_name=" + city,
type: "get",
success: function (data) {
console.log(data);
$("#result-text").text("");
$("#result-text").text(data.message);
var imagesrc = negative;
if (data.signal == 'positive') {
imagesrc = positive;
}
$("#result-image").html("");
$("#result-image").html("<img src='" + imagesrc + "' />");
hideLoader();
},
error: function (error) {
alert(error.message);
}
});
}
function showLoader()
{
$("#result-container").hide();
$("#loader").show();
}
function hideLoader()
{
$("#loader").hide();
$("#result-container").show();
}
app-config.jsonファイルのキーcommandの値を「node index.js」に更新します。これは、このプログラミングスタックとフレームワーク固有の起動コマンドです。
app-config.json
copy
{
"command": "node index.js",
"buildPath": "/Users/amelia-426/Catalyst/Alien City", // ビルドパスを指定してください
"stack": "node18",
"env_variables": {},
"memory": 256,
"scripts": {}
}
アプリケーションの動作を簡単に確認しましょう:
-
GETオペレーション
- アプリケーションで都市名を入力して過去のエイリアン遭遇の記録を確認すると、index.htmlのCheckボタンのonClickイベントがmain.jsで定義されたgetAlienEncounter()関数をトリガーします。
- これにより、index.js関数で定義されたURLルートにAjaxコールが発行されます。
- index.jsで定義されたGET APIがgetDataFromCatalystDataStore()関数を呼び出し、リクエストクエリを渡します。
- この関数は、ZCQLクエリを実行してData StoreのAlien Cityテーブル内のデータを検索します。
- テーブルで都市名に一致する記録が見つかった場合、レスポンスとしてpositiveシグナルが送信されます。見つからない場合は、negativeシグナルが送信されます。
- クライアントはレスポンスに対応するメッセージを表示します。main.jsで定義されたレスポンスに対応するGIFも表示されます。
-
POSTオペレーション
- クライアントで都市名を入力してエイリアン遭遇を報告すると、index.htmlのReportボタンのonClickイベントがmain.jsで定義されたpostAlienEncounter()関数をトリガーします。
- これにより、index.js関数で定義されたURLルートにAjaxコールが発行されます。index.jsで定義されたPOST APIがgetDataFromCatalystDataStore()関数を呼び出し、同じ都市名の記録が既に存在するかどうかを確認するリクエストクエリを渡します。
- この関数は、ZCQLクエリを実行してData StoreのAlien Cityテーブル内のデータを検索します。記録が既に存在する場合、レスポンスが送信され、アプリケーションはその都市名が既に追加されている旨のメッセージを表示します。
- 都市名の記録がない場合、ユーザーが入力した都市名でAlien Cityテーブルに新しい行が作成されます。クライアントにポップアップボックスが表示され、Data Storeへの記録の挿入が確認されます。適切なメッセージもログにプッシュされ、Catalyst DevOpsサービスのLogsコンポーネントから確認できます。
最終更新日 2026-03-05 11:43:24 +0530 IST