REST API のバックエンドを使った単一ページの Web アプリを作成するCreate a single-page web app with REST API backend

よく使われるフルスタックの Web テクノロジを使用して Microsoft Store 用のホストされた Web アプリを構築するBuild a Hosted Web App for the Microsoft Store with popular fullstack web technologies

単一ページの Web アプリである、簡単なメモリ ゲーム

2 つの部分から構成されるこのチュートリアルでは、モダンなフルスタックの Web 開発を簡単に紹介します。このチュートリアルでは、ブラウザーでも、Microsoft Store 用のホストされた Web アプリとしても動作する、簡単なメモリ ゲームを構築します。This two-part tutorial provides a quick tour of modern fullstack web development as you build a simple memory game that works both in the browser and as a Hosted Web App for the Microsoft Store. パート 1 では、ゲームのバックエンドのためのシンプルな REST API サービスを構築します。In Part I you'll build a simple REST API service for the game's backend. ゲーム ロジックをクラウドで API サービスとしてホストすることにより、ゲームの状態を保持することができ、ユーザーは異なるデバイスにわたって、ゲームの同じインスタンスのプレイを続けることができます。By hosting the game logic in the cloud as an API service, you preserve the game state so your user can keep playing their same game instance across different devices. パート 2 では、レスポンシブ レイアウトを使った単一ページの Web アプリとして、フロント エンド UI を構築します。In Part II you'll build the front-end UI as a single-page web app with responsive layout.

ここでは、サーバー側の開発のための Node.js ランタイムや ExpressBootstrap UI フレームワーク、RESTful API 構築のための Pug テンプレート エンジンや Swagger などの、よく使われる Web テクノロジを使用します。We'll be using some of the most popular web technologies, including the Node.js runtime and Express for server-side development, the Bootstrap UI framework, the Pug template engine, and Swagger for building RESTful APIs. さらに、クラウド ホスティングのための Azure Portal や、Visual Studio Code エディターの操作についても扱います。You'll also gain experience with the Azure Portal for cloud hosting and working with the Visual Studio Code editor.

前提条件Prerequisites

コンピューター上に次のようなリソースがない場合には、リンクを使ってダウンロードしてください。If you don't already have these resources on your machine, follow these download links:

最後のステップを完了して、API サービスとメモリ ゲーム アプリを Microsoft Azure でホスティングする場合には、無料の Azure アカウントを作成する必要があります (既に作成していない場合)。If you want to complete the final steps of hosting your API service and memory game app on Microsoft Azure, you'll need to create a free Azure account if you haven't already done so.

Azure の部分を行わない (または後で行う) 場合には、Azure のホスティングと、Microsoft Store 用のアプリのパッケージングについて説明している、パート 1 の最後のセクションとパート 2 を省略してください。If you decide to bail on (or postpone) the Azure part, simply skip the final sections of parts I and II, which cover Azure hosting and packaging your app for the Microsoft Store. その場合には、構築した API サービスと Webアプリをローカル コンピューター上で実行できます (それぞれ http://localhost:8000http://localhost:3000 から実行できます)。The API service and web app you build will still run locally (from http://localhost:8000 and http://localhost:3000, respectively) on your machine.

パート 1:REST API バックエンドの構築Part I: Build a REST API backend

最初に、簡単なメモリ ゲームの Web アプリを実現するための、メモリ ゲームの API を構築します。We'll first build a simple memory game API to power our memory game web app. Swagger を使って API を定義し、手動テストのためのスキャフォールディング コードと Web UI を生成します。We'll use Swagger to define our API and generate scaffolding code and a web UI for manual testing.

このパートを省略して、「パート 2: 単一ページの Web アプリケーションを構築する」に直接進む場合は、パート 1 の完成コードを利用できます。README の指示に沿って、ローカルでコードを実行するか、または「5. API サービスを Azure でホストして CORS を有効化する」を参照して Azure で実行します。If you'd like to skip this part and move straight to Part II: Build a single-page web application, here's the finished code for Part I. Follow the README instructions to get the code up and running locally, or see 5. Host your API service on Azure and enable CORS to run it from Azure.

ゲームの概要Game overview

メモリ (神経衰弱ペルマニズムとも呼ばれます) は、トランプのカードのペアを使った、簡単なゲームです。Memory (also known as Concentration and Pelmanism), is a simple game consisting of a deck of card pairs. カードはテーブル上に裏向きで配置され、プレイヤーは一度に 2 枚のカードを開いて、一致しているかどうかを確認します。The cards are placed face-down on the table, and the player inspects the card values, two at a time, looking for matches. 一致するペアが見つかったら、その 2 枚のカードはゲームからクリアされます。それ以外の場合には、2 枚とも裏向きに戻します。After each turn the cards are again placed face-down, unless a matching pair is found, in which case those two cards are cleared from the game. ゲームの目的は、できるだけ少ない回数で、すべてのカードのペアを見つけることです。The game objective is to find all card pairs in the fewest amount of turns.

ここでは説明用のため、ゲームの構造を非常にシンプルにし、ゲームは 1 回のみで、1 人のプレイヤーとしています。For instructional purposes, the game structure we'll use is very simple: it's single game, single player. ただし、ゲーム ロジックを (クライアントでなく) サーバー側に配置し、ゲームの状態を保存できるようにします。これによって、異なるデバイスにわたって、同じゲームのプレイを続けることができます。However, the game logic is server-side (rather than on the client) to preserve the game state, so that you could keep playing the same game across different devices.

メモリ ゲームのデータ構造は、JavaScript オブジェクトの配列のみで構成されます。それぞれが 1 つのカードを表し、配列内のインデックスを持ち、これがカード ID として機能します。The data structure for a memory game consists simply of an array of JavaScript objects, each representing a single card, with indices in the array acting as card IDs. サーバー上では、各カード オブジェクトが 1 つの値と cleared フラグを持ちます。On the server, each card object has a value and a cleared flag. たとえば、2 組のペア (4 枚のカード) から成るゲーム ボードは、ランダムに生成されて、次のようにシリアル化されます。For example, a board of 2-matches (4 cards) might be randomly generated and serialized like this.

[
    { "cleared":"false",
        "value":"0",
    },
    { "cleared":"false",
        "value":"1",
    },
    { "cleared":"false",
        "value":"1",
    },
    { "cleared":"false",
        "value":"0",
    }
]

ボードの配列がクライアントに渡されると、不正を防ぐために (たとえば、ブラウザーの F12 ツールを使って、HTTP 応答の本文を検査するなど)、value キーを配列から削除します。When the board array is passed to the client, value keys are removed from the array to prevent cheating (for example, inspecting the HTTP response body by using F12 browser tools). GET /game REST エンドポイントを呼び出すクライアントに対して、新しい同じゲームは次のようになります。Here's how that same new game would look to a client calling the GET /game REST endpoint:

[{ "cleared":"false"},{ "cleared":"false"},{ "cleared":"false"},{ "cleared":"false"}]

エンドポイントについては、メモリ ゲーム サービスは、次の 3 つの REST API で構成されます。Speaking of endpoints, the memory game service will consist of three REST APIs.

POST /newPOST /new

指定されたサイズで (数字はペアの数を表します) 新しいゲーム ボードを初期化します。Initializes a new game board of the specified size (# of matches).

パラメーターParameter 説明Description
int sizeint size ゲーム ボードに含まれる、一致するペアの数。Number of matching pairs to be shuffled into the game "board". 例: http://memorygameapisample/new?size=2Example: http://memorygameapisample/new?size=2
応答Response 説明Description
200 OK200 OK 要求されたサイズの新しいメモリ ゲームの準備ができました。New memory game of requested size is ready.
400 BAD REQUEST400 BAD REQUEST 要求されたサイズは、許容範囲外です。Requested size is outside of acceptable range.

GET /gameGET /game

メモリ ゲーム ボードの現在の状態を取得します。Retrieves the current state of the memory game board.

パラメーターなしNo parameters

応答Response 説明Description
200 OK200 OK カード オブジェクトの JSON 配列を返します。Returns JSON array of card objects. 各カードには、ペアが既に見つかったことを示す、cleared プロパティがあります。Each card has a cleared property indicating whether its match has already been found. 一致したカードは、その value も報告します。Matched cards also report their value. 例: [{"cleared":"false"},{"cleared":"false"},{"cleared":"true","value":1},{"cleared":"true","value":1}]Example: [{"cleared":"false"},{"cleared":"false"},{"cleared":"true","value":1},{"cleared":"true","value":1}]

PUT /guessPUT /guess

表向きにするカードを指定し、前に表向きにしたカードとの一致を確認します。Specifies a card to reveal and checks for a match to the previously revealed card.

パラメーターParameter 説明Description
int cardint card 表向きにするカードのカード ID (ゲーム ボード配列内のインデックス)。Card ID (index in game board array) of the card to reveal. 完了した各「推測」は、指定された 2 枚のカード (つまり、有効で一意の card 値 を持つ、2 つの /guess の呼び出し) で構成されます。Each complete "guess" consists of two specified cards (i.e., two calls to /guess with valid and unique card values). 例: http://memorygameapisample/guess?card=0Example: http://memorygameapisample/guess?card=0
応答Response 説明Description
200 OK200 OK 指定されたカードの idvalue を持つ JSON を返します。Returns JSON with the id and value of the specified card. 例: [{"id":0,"value":1}]Example: [{"id":0,"value":1}]
400 BAD REQUEST400 BAD REQUEST 指定されたカードでエラーが発生しました。Error with the specified card. 詳細は HTTP 応答の本文を参照してください。See HTTP response body for further details.

1. API を指定して、コード スタブを生成する1. Spec out the API and generate code stubs

Swagger を使って、メモリ ゲームの API の設計を、動作する Node.js サーバー コードに変換します。We'll use Swagger to transform the design of our memory game API into working Node.js server code. 次のようにして、メモリ ゲーム API を Swagger メタデータとして定義できます。Here's how you might define our memory game APIs as Swagger metadata. これを使って、サーバー コードのスタブを生成します。We'll use this to generate server code stubs.

  1. 新しいフォルダー (たとえば、ローカルの GitHub ディレクトリ) を作成し、メモリ ゲーム API 定義を含む api.json ファイルをダウンロードします。Create a new folder (in your local GitHub directory, for example), and download the api.json file containing our memory game API definitions. フォルダー名にスペースが含まれていないことを確認します。Make sure your folder name doesn't contain any spaces.

  2. このフォルダーで好みのシェル (または Visual Studio Code の統合ターミナル) を開き、次の Node Package Manager (NPM) コマンドを実行して、Yeoman (yo) コード スキャフォールディング ツールおよび Swagger ジェネレーターをグローバル ( -g) Node 環境にインストールします。Open your favorite shell (or use Visual Studio Code's integrated terminal!) to that folder and run the following Node Package Manager (NPM) command to install the Yeoman (yo) code-scaffolding tool and Swagger generator for your global (-g) Node environment:

    npm install -g yo
    npm install -g generator-swaggerize
    
  3. Swagger を使用して、サーバー スキャフォールディング コードを生成します。Now we can generate the server scaffolding code by using Swagger:

    yo swaggerize
    
  4. Swaggerize コマンドの質問のメッセージに応答します。The swaggerize command will ask you several questions.

    • Swagger ドキュメントへのパス (またはURL): api.jsonPath (or URL) to swagger document: api.json
    • フレームワーク: expressFramework: express
    • プロジェクト名 (YourFolderNameHere): [Enter]What would you like to call this project (YourFolderNameHere): [enter]

    他は適宜に応答します。これらの情報の多くは package.json ファイルに連絡先情報を指定するために使用され、作成したコードを NPM パッケージとして配布できます。Answer everything else as you like; the information is mostly to supply the package.json file with your contact info so you can distribute your code as an NPM package.

  5. 最後に、新しいプロジェクトのすべての依存関係 (package.json に一覧表示されています) および Swagger UI サポートをインストールします。Finally, install all the dependencies (listed in package.json) for your new project and Swagger UI support.

    npm install
    npm install swaggerize-ui
    

    VS Code を開始し、 [ファイル] > [フォルダーを開く] と選び、MemoryGameAPI ディレクトリに移動します。Now start VS Code and File > Open Folder..., and move to the MemoryGameAPI directory. これは、先ほど作成した Node.js API サーバーです。This is the Node.js API server you just created! これは、よく使われる ExpressJS Web アプリケーション フレームワークを使って、プロジェクトを構造化して実行します。It uses the popular ExpressJS web application framework to structure and run your project.

2. サーバー コードのカスタマイズとデバッグのセットアップ2. Customize the server code and setup debugging

プロジェクト ルートの server.js ファイルが、サーバーの「メイン」の機能を果たします。The server.js file in your project root acts as the "main" function of your server. そのファイルを VS Code で開き、そこに次のコードをコピーします。Open it in VS Code and copy the following into it. 生成されたコードを変更した行には、詳しい説明のコメントが入っています。The lines modified from the generated code are commented with further explanation.

'use strict';

var port = process.env.PORT || 8000; // Better flexibility than hardcoding the port

var Http = require('http');
var Express = require('express');
var BodyParser = require('body-parser');
var Swaggerize = require('swaggerize-express');
var SwaggerUi = require('swaggerize-ui'); // Provides UI for testing our API
var Path = require('path');

var App = Express();
var Server = Http.createServer(App);

App.use(function(req, res, next) {  // Enable cross origin resource sharing (for app frontend)
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

    // Prevents CORS preflight request (for PUT game_guess) from redirecting
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next(); // Passes control to next (Swagger) handler
    }
});

App.use(BodyParser.json());
App.use(BodyParser.urlencoded({
    extended: true
}));

App.use(Swaggerize({
    api: Path.resolve('./config/swagger.json'),
    handlers: Path.resolve('./handlers'),
    docspath: '/swagger'   //  Hooks up the testing UI
}));

App.use('/', SwaggerUi({    // Serves the testing UI from our base URL
  docs: '/swagger'          //
}));

Server.listen(port, function () {  // Starts server with our modfied port settings
 });

これでサーバーを実行する準備ができました。With that, it's time to run your server! Visual Studio Code で、Node のデバックを行うように設定します。Let's set up Visual Studio Code for Node debugging while we're at it. デバッグ パネル アイコン (Ctrl+Shift+D) を選び、次に歯車アイコンを選んで (launch.json を開く)、"configurations" を次のように変更します。Select on the Debug panel icon (Ctrl+Shift+D) and then the gear icon (Open launch.json), and modify "configurations" to this:

"configurations": [
    {
        "type": "node",
        "request": "launch",
        "name": "Launch Program",
        "program": "${workspaceRoot}/server.js"
    }
]

F5 キーを押してブラウザーを開き、https://localhost:8000 に移動します。Now press F5 and open your browser to https://localhost:8000. メモリ ゲーム API の Swagger UI のページが開きます。詳細を展開して、各メソッドのフィールドを入力します。The page should open to the Swagger UI for our memory game API, and from there you can expand the details and input fields for each of the methods. API の呼び出しを試すこともできますが、応答には (Swagmock モジュールが提供する) モックアップ データのみが含まれています。You can even try calling the APIs, although their responses will contain only mocked-up data (provided by the Swagmock module). 次に、API が実際に動作するように、ゲーム ロジックを追加します。It's time to add our game logic to make these APIs real.

3.ルート ハンドラーを設定する3. Set up your route handlers

Swagger ファイル (config\swagger.json) では、定義されている各 URL パスを (\handlers にある) ハンドラー ファイルにマッピングし、さらにそのパスに定義された各メソッド (GETPOST など) をハンドラー ファイル内の operationId (機能) にマッピングして、サーバーに対して、さまざまなクライアントの HTTP 要求を処理する方法を指示します。The Swagger file (config\swagger.json) instructs our server how to handle various client HTTP requests by mapping each URL path it defines to a handler file (in \handlers), and each method defined for that path (e.g., GET, POST) to an operationId (function) within that handler file.

プログラムのこのレイヤーには、さまざまなクライアント要求をデータ モデルに渡す前に、いくつかの入力チェックを追加します。In this layer of our program we'll add some input checking before passing the various client requests to our data model. 次をダウンロード (またはコピーして貼り付け) して利用できます。Download (or copy and paste):

  • この game.js コードを handlers\game.js ファイルに使いますThis game.js code to your handlers\game.js file
  • この guess.js コードを handlers\guess.js ファイルに使いますThis guess.js code to your handlers\guess.js file
  • この new.js コードを handlers\new.js ファイルに使いますThis new.js code to your handlers\new.js file

それぞれの変更の詳細については、ファイル内のコメントを確認してください。ここでは、基本的な入力エラーの確認 (たとえば、新しいゲームのクライアント要求でペアの数が 1 より少ないなど) を行い、必要に応じてエラーメッセージを送信しています。You can skim the comments in those files for more details about the changes, but in essence they check for basic input errors (for example, the client requests a new game with less than one match) and send descriptive error messages as needed. またハンドラーは、有効なクライアント要求を、(\data にある) 対応するデータ ファイルにルーティングして、さらに処理を行うようにします。The handlers also route valid client requests through to their corresponding data files (in \data) for further processing. これらは次で行います。Let's work on those next.

4。データ モデルをセットアップする4. Set up your data model

プレースホルダーのモックデータ サービスを、実際のメモリ ゲーム ボードのデータ モデルに置き換えます。It's time to swap out the placeholder data-mocking service with a real data model of our memory game board.

プログラムのこのレイヤーは、メモリ カード自体を表し、ゲーム ロジックのほとんどを提供します。これには、新しいゲームのためのカードのシャッフル、一致したカードのペアの認識、ゲーム状態の記録などが含まれます。This layer of our program represents the memory cards themselves and provides the bulk of the game logic, including "shuffling" the deck for a new game, identifying pairs of matched cards, and keeping track of game state. 次をコピーして貼り付けて利用できます。Copy and paste:

  • この game.js コードを data\game.js ファイルに使いますThis game.js code to your data\game.js file
  • この guess.js コードを data\guess.js ファイルに使いますThis guess.js code to your data\guess.js file
  • この new.js コードを data\new.js ファイルに使いますThis new.js code to your data\new.js file

ここでは簡単のため、ゲーム ボードを Node サーバーのグローバル変数 (global.board) に保存します。For simplicity, we're storing our game board in a global variable (global.board) on our Node server. 同時に複数のプレイヤーによる複数のゲームをサポートする、実際に使えるメモリ ゲーム API サービスとするためには、クラウド ストレージ (Google Cloud Datastore や Azure DocumentDB など) を使用します。But realistically you'd use cloud storage (like Google Cloud Datastore or Azure DocumentDB) to make this into a viable memory-game API service that concurrently supports multiple games and players.

VS Code ですべての変更を保存したことを確認し、サーバーを再度起動 (VS Code で F5 キーを押すか、またはシェルから npm start を実行して、次に https://localhost:8000 に移動する) して、ゲームの API をテストします。Make sure you've saved all the changes in VS Code, fire up your server again (F5 in VS Code or npm start from shell, and then browse to https://localhost:8000) to test out the game API.

Try it out! ボタンをEach time you press the Try it out! /game/guess/new のいずれかで押して、下の Response Body および Response Code の結果を確認し、予想どおりに動作していることを確認します。button on one of the /game, /guess, or /new operations, check the resulting Response Body and Response Code below to verify that everything's working as expected.

次のように試してみます。Try:

  1. 新しい size=2 のゲームを作成します。Creating a new size=2 game.

    Swagger UI から新しいメモリ ゲームを開始する

  2. いくつかの値を推測します。Guessing a couple of values.

    Swagger UI からカードを推測する

  3. ゲームを進行しながら、ゲーム ボードを確認します。Checking the game board as the game progresses.

    Swagger UI からゲームの状態を確認する

すべての動作を確認したら、API サービスを Azure でホストします。If everything looks good, your API service is ready to host on Azure! 問題が発生した場合には、\data\game.js で、次の行をコメント アウトしてみます。If you're running into problems, try commenting out the following lines in \data\game.js.

for (var i=0; i < board.length; i++){
    var card = {};
    card.cleared = board[i].cleared;

    // Only reveal cleared card values
    //if ("true" == card.cleared) {        // To debug the board, comment out this line
        card.value = board[i].value;
    //}                                    // And this line
    currentBoardState.push(card);
}

この変更により、GET /game メソッドは (クリアされていないものも含めて) すべてのカードの値を返します。With this change, the GET /game method will return all the card values (including the ones that haven't been cleared). これは、メモリ ゲームのフロント エンドを構築する際のデバッグに役立ちます。This is a useful debug hack to keep in place as you build the front-end for the memory game.

5。(省略可能) API サービスを Azure でホストして CORS を有効化する5. (Optional) Host your API service on Azure and enable CORS

次の Azure ドキュメントを参照して作業を行います。The Azure docs will walk you through:

アプリを登録する場合、アプリ名を他と異なるものにするようにします ( http://memorygameapi.azurewebsites.net URL のバリエーションを要求する、他のアプリと名前が競合しないようにします)。When registering your app, try to differentiate your App name (to avoid naming collisions with others requesting variations on the http://memorygameapi.azurewebsites.net URL).

ここまでの作業を行って、Azure と Swagger UI が機能している場合、メモリ ゲームのバックエンドに必要な最後の手順が 1 つあります。If you've made it this far and Azure is now serving up your swagger UI, there's just one final step to the memory game backend. Azure Portal から、新しく作成したアプリ サービスを選び、CORS (クロス オリジン リソース共有) オプションを選択または検索します。From Azure Portal, select your newly created App Service and then select or search for the CORS (Cross-Origin Resource Sharing) option. [許可されたオリジン] の下で、アスタリスク (*) を追加して、 [保存] をクリックします。Under Allowed Origins, add an asterisk (*) and click Save. これにより、ローカル マシンで開発を行いながら、メモリ ゲームのフロントエンドから、作成した API サービスへのクロス オリジンの呼び出しが可能となります。This lets you make cross-origin calls to your API service from your memory-game front-end as you develop it on your local machine. メモリ ゲームのフロント エンドが完成し、Azure にデプロイしたら、このエントリを Web アプリの特定の URL で置き換えることができます。Once you finalize the memory-game front-end and deploy that to Azure, you can replace this entry with the specific URL of your web app.

追加情報Going further

メモリ ゲーム API を実稼働アプリ用のバックエンド サービスとするためには、複数のプレイヤーとゲームをサポートするようにコードを拡張する必要があります。To make the memory game API a viable back-end service for a production app, you'll want to extend the code to support multiple players and games. そのためには、認証 (プレイヤーの ID を管理する)、NoSQL データベース (ゲームとプレイヤーを管理する)、API の基本的な単体テストについて調べる必要があります。For that you'll probably need to plumb in authentication (for managing player identities), a NoSQL database (for tracking games and players), and some basic unit testing for your API.

そのために役立つ追加情報を次に示します。Here are some useful resources for going further:

パート 2:単一ページの Web アプリケーションを構築するPart II: Build a single-page web application

パート 1 では、REST API バックエンドを構築 (またはダウンロード) しました。次に、NodeExpressBootstrap を使って、単一ページのメモリ ゲームのフロントエンドを作成します。Now that you've built (or downloaded) the REST API backend from Part I, you're ready to create the single-page memory game front-end with Node, Express, and Bootstrap.

このチュートリアルのパート 2 では、次の内容を扱います。Part II of this tutorial will give you experience with:

  • Node.js: ゲームをホストするサーバーの作成Node.js: to create the server hosting your game
  • jQuery: JavaScript ライブラリjQuery: a JavaScript library
  • Express: Web アプリケーション フレームワークExpress: for the web application framework
  • Pug: (旧 Jade) テンプレート エンジンPug: (formerly Jade) for the templating engine
  • Bootstrap: レスポンシブ レイアウトBootstrap: for the responsive layout
  • Visual Studio Code: コードの作成、マークダウン表示、デバッグVisual Studio Code: for code authoring, markdown viewing, and debugging

1. Express を使って Node.js アプリケーションを作成する1. Create a Node.js application by using Express

まず、Express を使って Node.js プロジェクトを作成します。Let's start by creating the Node.js project using Express.

  1. コマンド プロンプトを開き、ゲームの保存先のディレクトリに移動します。Open a command prompt and navigate to the directory where you want to store your game.

  2. Express ジェネレーターを使い、テンプレート エンジン Pug を使用して、新しいアプリケーション memory を作成します。Use the Express generator to create a new application called memory using the templating engine, Pug.

    express --view=pug memory
    
  3. memory ディレクトリで、package.json ファイルに示されている依存関係をインストールします。In the memory directory, install the dependencies listed in the package.json file. package.json ファイルは、プロジェクトのルートに作成されます。The package.json file is created in the root of your project. このファイルには、Node.js アプリに必要なモジュールが含まれています。This file contains the modules that are required for your Node.js app.

    cd memory
    npm install
    

    このコマンドを実行すると、このアプリに必要なすべてのモジュールを含む、node_modules という名前のフォルダーが作成されます。After running this command, you should see a folder called node_modules that contains all of the modules needed for this app.

  4. アプリケーションを実行します。Now, run your application.

    npm start
    
  5. https://localhost:3000/ に移動してアプリケーションを表示します。View your application by going to https://localhost:3000/.

    http://localhost:3000/ のスクリーンショット

  6. memory\routes ディレクトリの index.js を編集して、Web アプリの既定のタイトルを変更します。Change the default title of your web app by editing index.js in the memory\routes directory. 下記の行の ExpressMemory Game (または任意のタイトル) に変更します。Change Express in the line below to Memory Game (or another title of your choosing).

    res.render('index', { title: 'Express' });
    
  7. 新しいタイトルを表示するためアプリを更新するには、コマンド プロンプトで Ctrl + CY の順に押してアプリを停止し、npm start で再起動します。To refresh the app to see your new title, stop your app by pressing Crtl + C, Y in the command prompt, and then restart it with npm start.

2. クライアント側のゲーム ロジック コードを追加する2. Add client-side game logic code

チュートリアルのこの後半に必要なファイルは、Start フォルダーに含まれています。You can find the files you need for this half of the tutorial in the Start folder. 途中で迷った場合には、Final フォルダーに完成したコードが含まれています。If you get lost, the finished code is available in the Final folder.

  1. Start フォルダー内の scripts.js ファイルをコピーして、それを memory\public\javascripts に貼り付けます。Copy the scripts.js file inside of the Start folder and paste it in memory\public\javascripts. このファイルには、次のような、ゲームを実行するために必要なすべてのゲーム ロジックが含まれています。This file contains all the game logic needed to run the game, including:

    • 新しいゲームを作成/開始します。Creating/starting a new game.
    • サーバーに保存されているゲームを復元します。Restoring a game stored on the server.
    • ユーザーの選択に基づいて、ゲーム ボードとカードを描画します。Drawing the game board and cards based on user selection.
    • カードを反転します。Flipping the cards.
  2. script.js で、まず newGame() 関数を変更します。In script.js, let's start by modifying the newGame() function. この関数は次の処理を行います。This function:

    • ユーザーからのゲームのサイズの選択を処理します。Handles the size of the game selection from the user.
    • サーバーから gameboard array をフェッチします。Fetches the gameboard array from the server.
    • drawGameBoard() 関数を呼び出し、画面にゲーム ボードを配置します。Calls the drawGameBoard() function to place the game board to the screen.

    newGame() 内の // Add code from Part 2.2 here コメントの後に、次のコードを追加します。Add the following code inside of newGame() after the // Add code from Part 2.2 here comment.

    // extract game size selection from user
    var size = $("#selectGameSize").val();
    
    // parse game size value
    size = parseInt(size, 10);
    

    このコードは、id="selectGameSize" (これは後で作成します) を使って、ドロップダウン メニューから値を取得し、それを変数 (size) に保存します。This code retrieves the value from the dropdown menu with id="selectGameSize" (which we will create later) and stores it in a variable (size). parseInt() 関数を使って、ドロップダウンからの文字列の値を解析して整数を返します。要求されたゲーム ボードの size をサーバーに渡します。We use the parseInt() function to parse the string value from the dropdown to return an integer, so we can pass the size of the requested game board to the server.

    このチュートリアルのパート 1 で作成した /new メソッドを使って、選択されたゲーム ボードのサイズをサーバーに投稿します。We use the /new method created in Part I of this tutorial to post the chosen size of the game board to the server. このメソッドは、カードおよびカードが一致したかどうかを示す true/false 値を含む、単一の JSON 配列を返します。The method returns a single JSON array of cards and true/false values indicating whether the cards have been matched.

  3. 次に、restoreGame() 関数に入力します。この関数は最後にプレイされたゲームを復元します。Next, fill in the restoreGame() function that restores the last game played. 簡単のため、このアプリでは最後にプレイされたゲームを常に読み込みます。For simplicity's sake, the app always loads the last game played. サーバーに保存されているゲームがない場合、ドロップ ダウン メニューを使用して新しいゲームを開始します。If there is not a game stored on the server, use the drop-down menu to start a new game.

    次のコードをコピーして restoreGame() に貼り付けます。Copy and paste this code into restoreGame().

    // reset the game
    gameBoardSize = 0;
    cardsFlipped = 0;
    
    // fetch the game state from the server 
    $.get("http://localhost:8000/game", function (response) {
        // store game board size
        gameBoardSize = response.length;
    
        // draw the game board
        drawGameBoard(response);
    });
    

    ゲームで、サーバーからゲームの状態をフェッチできるようになります。The game will now fetch the game state from the server. この手順で使用されている /game メソッドの詳細については、このチュートリアルの第 I 部を参照してください。For more information about the /game method being used in this step, see Part I of this tutorial. Azure (または別のサービス) を使用してバックエンド API をホストしている場合、上記の localhost を実稼働 URL に置き換えます。If you are using Azure (or another service) to host the backend API, replace the localhost address above with your production URL.

  4. 次に、drawGameBoard() 関数を作成します。Now we want to create the drawGameBoard() function. この関数は次の処理を行います。This function:

    • ゲームのサイズを検出し、特定の CSS スタイルを適用します。Detects the size of the game and applies specific CSS styles.
    • HTML でカードを生成します。Generates the cards in HTML.
    • カードをページに追加します。Adds the cards to the page.

    次のコードをコピーして、scripts.jsdrawGameBoard() 関数に貼り付けます。Copy and paste this code into the drawGameBoard() function in scripts.js:

    // create output
    var output = "";
    // detect board size CSS class
    var css = "";
    switch (board.length / 4) {
        case 1:
            css = "rows1";
            break;
        case 2:
            css = "rows2";
            break;
        case 3:
            css = "rows3";
            break;
        case 4:
            css = "rows4";
            break;   
    }
    // generate HTML for each card and append to the output
    for (var i = 0; i < board.length; i++) {
        if (board[i].cleared == "true") {
            // if the card has been cleared apply the .flip class
            output += "<div class=\"flipContainer col-xs-3 " + css + "\"><div class=\"cards flip matched\" id=\"" + i + "\" onClick=\"flipCard(this)\">\
                <div class=\"front\"><span class=\"glyphicon glyphicon-question-sign\"></span></div>\
                <div class=\"back\">" + lookUpGlyphicon(board[i].value) + "</div>\
                </div></div>";
        } else {
            output += "<div class=\"flipContainer col-xs-3 " + css + "\"><div class=\"cards\" id=\"" + i + "\" onClick=\"flipCard(this)\">\
                <div class=\"front\"><span class=\"glyphicon glyphicon-question-sign\"></span></div>\
                <div class=\"back\"></div>\
                </div></div>";
        }
    }
    // place the output on the page
    $("#game-board").html(output);
    
  5. 次に、flipCard() 関数を完成させます。Next, we need to complete the flipCard() function. この関数では、チュートリアルのパート 1 で開発した /guess メソッドを使って、選んだカードの値をサーバーから取得するなど、ゲーム ロジックの大部分の処理を行います。This function handles the majority of the game logic, including getting the values of the selected cards from the server by using the /guess method developed in Part I of the tutorial. REST API バックエンドをクラウドでホスティングしている場合には、localhost アドレスを運用 URL に忘れずに置換します。Don't forget to replace the localhost address with your production URL if you are cloud hosting the REST API backend.

    flipCard() 関数で、次のコードのコメントを解除します。In the flipCard() function, uncomment this code:

    // post this guess to the server and get this card's value
    $.ajax({
        url: "http://localhost:8000/guess?card=" + selectedCards[0],
        type: 'PUT',
        success: function (response) {
            // display first card value
            $("#" + selectedCards[0] + " .back").html(lookUpGlyphicon(response[0].value));
    
            // store the first card value
            selectedCardsValues.push(response[0].value);
        }
    });
    

ヒント

Visual Studio Code を使っている場合は、コメントを解除するコードのすべての行を選択して、Crtl + K、U キーの順に押します。If you're using Visual Studio Code, select all the lines of code you wish to uncomment, and press Crtl + K, U

次に、jQuery.ajax() と、パート 1 で作成した PUT/guess メソッドを使用します。Here we use jQuery.ajax() and the PUT /guess method created in Part I.

このコードは、次の順序で実行されます。This code executes in the following order.

  • ユーザーが選択した最初のカードの id が、selectedCards[] 配列の最初の値として追加されます: selectedCards[0]The id of the first card the user selected is added as the first value to the selectedCards[] array: selectedCards[0]
  • selectedCards[0] の値 (id) が /guess メソッドを使ってサーバーに投稿されますThe value (id) in selectedCards[0] is posted to the server using the /guess method
  • サーバーが、そのカードの value (整数) を応答しますThe server responds with the value of that card (an integer)
  • idselectedCards[0] であるカードの裏に Bootstrap glyphicon が追加されますA Bootstrap glyphicon is added to the back of the card whose id is selectedCards[0]
  • (サーバーからの) 最初のカードの valueselectedCardsValues[] 配列: selectedCardsValues[0] に保存されますThe first card's value (from the server) is stored in the selectedCardsValues[] array: selectedCardsValues[0].

ユーザーの 2 回目の推測も同じロジックに従います。The user's second guess follows the same logic. ユーザーが選択したカードが同じ ID である場合 (たとえば selectedCards[0] == selectedCards[1])、カードは一致します。If the cards that the user selected have the same IDs, (for example, selectedCards[0] == selectedCards[1]), the cards are a match! 一致したペアには CSS クラス .matched が追加され (緑色に変わり)、カードは反転されたまま残ります。The CSS class .matched is added to the matched cards (turning them green) and the cards remained flipped.

ここで、すべてのカードが一致し、ゲームが終了したかどうかを確認するロジックを追加します。Now we need to add logic to check whether the user matched all of the cards and won the game. flipCard() 関数の中で //check if the user won the game コメントの下に、次の行を追加します。Inside of the flipCard() function, add the following lines of code under the //check if the user won the game comment.

if (cardsFlipped == gameBoardSize) {
    setTimeout(function () {
        output = "<div id=\"playAgain\"><p>You Win!</p><input type=\"button\" onClick=\"location.reload()\" value=\"Play Again\" class=\"btn\" /></div>";
        $("#game-board").html(output);
    }, 1000);
}   

反転して一致したカードの数が、ゲーム ボードのサイズと等しい場合 (たとえば、cardsFlipped == gameBoardSize)、それ以上反転できるカードはなく、ゲームは終了です。If the number of cards flipped matches the size of the game board (for example, cardsFlipped == gameBoardSize), there are no more cards to flip and the user has won the game. divid="game-board" を使って簡単な HTML を追加して、ユーザーにゲームが終了したことと、もう一度プレイできることを伝えます。We'll add some simple HTML to the div with id="game-board" to let the user know they won and can play again.

3.ユーザー インターフェイスを作成する3. Create the user interface

次に、すべてのコードを確認して、ユーザー インターフェイスを作成します。Now let's see all this code in action by creating the user interface. このチュートリアルでは、テンプレート エンジン Pug (旧 Jade) を使用します。In this tutorial, we use the templating engine Pug (formally Jade). Pug では HTML の記述時に、空白が意味を持つ、クリーンな構文を使います。Pug is clean, whitespace-sensitive syntax for writing HTML. 次に例を示します。Here's an example.

body
    h1 Memory Game
    #container
        p We love tutorials!

上記は以下のようになります。becomes

<body>
    <h1>Memory Game</h1>
    <div id="container">
        <p>We love tutorials!</p>
    </div>
</body>
  1. memory\views の layout.pug ファイルを、提供された Start フォルダーの layout.pug ファイルで置き換えます。Replace the layout.pug file in memory\views with the provided layout.pug file in the Start folder. layout.pug の中には、次へのリンクが含まれています。Inside of layout.pug, you'll see links to:

    • BootstrapBootstrap
    • jQueryjQuery
    • カスタム CSS ファイルA custom CSS file
    • 変更が完了した JavaScript ファイルThe JavaScript file we just finished modifying
  2. memory\views ディレクトリで index.pug という名前のファイルを開きます。Open the file named index.pug in the directory memory\views. このファイルは、layout.pug ファイルを拡張し、ゲームのレンダリングを行います。This file extends the layout.pug file and will render our game. layout.pug の中に、次のコードを貼り付けます。Inside of layout.pug, paste the following lines of code:

    extends layout
    block content  
        div
            form(method="GET")
            select(id="selectGameSize" class="form-control" onchange="newGame()")
                option(value="0") New Game
                option(value="2") 2 Matches
                option(value="4") 4 Matches
                option(value="6") 6 Matches
                option(value="8") 8 Matches         
            #game-board
                script restoreGame();
    

ヒント

注意: Pug では空白が意味を持ちます。Remember: Pug is whitespace sensitive. すべてのインデントが正しいことを確認します。Make sure all of your indentations are correct!

4。Bootstrap のグリッドのシステムを使ってレスポンシブ レイアウトを作成する4. Use Bootstrap's grid system to create a responsive layout

Bootstrap のグリッド システムは、デバイスのビューポートの変化にしたがって拡大縮小する、柔軟なグリッド システムです。Bootstrap's grid system is a fluid grid system that scales a grid as a device's viewport changes. このゲームのカードは、次のような Bootstrap の定義済みのグリッド システム クラスをレイアウトに使用しています。The cards in this game use Bootstrap's predefined grid system classes for the layout, including:

  • .container-fluid: 柔軟なグリッド コンテナーを指定します.container-fluid: specifies the fluid container for the grid
  • .row-fluid: 柔軟な行を指定します.row-fluid: specifies the fluid rows
  • .col-xs-3: 列数を指定します.col-xs-3: specifies the number of columns

Bootstrap のグリッド システムを使うと、モバイル デバイスのナビゲーション メニューに表示されるように、グリッド システムを 1 つの垂直列に折りたたむことができます。Bootstrap's grid system allows a grid system to collapse into one vertical column, like you would see on a navigation menu on a mobile device. しかし、このゲームでは常に列を保持するため、定義済みのクラス .col-xs-3 を使い、常に横方向のグリッドを保持するようにします。However, because we want our game always to have columns, we use the predefined class .col-xs-3, which keeps the grid horizontal at all times.

このグリッド システムでは最大 12 列が可能です。The grid system allows up to 12 columns. このゲームでは 4 列のみを使用するため、.col-xs-3 クラスを使用します。Since we only want 4 columns in our game, we use the class .col-xs-3. このクラスは、前述の利用可能な 12 列のうちの 3 列の幅にわたる、各列を必要とすることを指定します。This class specifies that we need each of our columns to span the width of 3 of the 12 available columns mentioned before. 次の図は、このゲームで使われている、12 列のグリッドと 4 列のグリッドを示します。This image shows a 12-column grid and a 4-column grid, like the one used in this game.

Bootstrap の 12 列と 4 列のグリッド

  1. scripts.js を開き、drawGameBoard() 関数を見つけます。Open scripts.js and find the drawGameBoard() function. 各カードの HTML を生成したコード ブロックで、class="col-xs-3" を持つ div 要素を見つけます。In the block of code where we generate the HTML for each card, can you spot the div element with class="col-xs-3"?

  2. index.pug の中に、先述の定義済みの Bootstrap のクラスを追加して、柔軟なレイアウトを作成します。Inside of index.pug, let's add the predefined Bootstrap classes mentioned previously to create our fluid layout. index.pug を次のように変更します。Change index.pug to the following.

    extends layout
    
    block content   
    
        .container-fluid
            form(method="GET")
            select(id="selectGameSize" class="form-control" onchange="newGame()")
                option(value="0") New Game
                option(value="2") 2 Matches
                option(value="4") 4 Matches
                option(value="6") 6 Matches
                option(value="8") 8 Matches         
            #game-board.row-fluid 
                script restoreGame();
    

5。CSS 変換を使ってカードの反転のアニメーションを追加する5. Add a card-flip animation with CSS Transforms

memory\public\stylesheets の style.css ファイルを、Start フォルダーの style.css ファイルで置き換えます。Replace the style.css file in memory\public\stylesheets with the style.css file from the Start folder.

CSS 変換を使って、反転モーションを追加し、カードにリアルな 3D の反転モーションを追加します。Adding a flip motion using CSS Transforms gives the cards a realistic, 3D flipping motion. ゲームのカードは次の HTML 構造を使用して作成され、(先述の drawGameBoard()関数により) プログラムによってゲーム ボードに追加されています。The cards in the game are created by using the following HTML structure and programmatically added to the game board (in the drawGameBoard() function shown previously).

<div class="flipContainer">
    <div class="cards">
        <div class="front"></div>
        <div class="back"></div>
    </div>
</div>
  1. まず、アニメーションの親コンテナーに視点を与えます (.flipContainer)。To start, give perspective to the parent container of the animation (.flipContainer). これにより、子要素に深度の錯視が加わります。値が大きいほど、要素はユーザーがから離れて見えます。This gives the illusion of depth for its child elements: the higher the value, the farther away from the user the element will appear. style.css の .flipContainer クラスに、次の視点を追加します。Let's add the following perspective to the .flipContainer class in style.css.

    perspective: 1000px; 
    
  2. 次に、style.css の .cards クラスに以下のプロパティを追加します。Now add the following properties to the .cards class in style.css. .cards div は、カードの表または裏を示して、実際に反転アニメーションを行う要素です。The .cards div is the element that will actually be doing the flipping animation, showing either the front or the back of the card.

    transform-style: preserve-3d;
    transition-duration: 1s;
    

    transform-style プロパティは 3D レンダリングのコンテキストを確立します。.cards クラスの子 (.front および .back) は 3D 空間のメンバーです。The transform-style property establishes a 3D-rendering context, and the children of the .cards class (.front and .back are members of the 3D space. transition-duration プロパティを追加して、アニメーションを完了する時間を秒数で指定します。Adding the transition-duration property specifies the number of seconds for the animation to finish.

  3. transform プロパティを使って、カードを Y 軸周りで回転させることができます。Using the transform property, we can rotate the card around the Y-axis. 次の CSS を cards.flip に追加します。Add the following CSS to cards.flip.

    transform: rotateY(180deg);
    

    cards.flip で定義されたスタイルは、flipCard 関数で .toggleClass() を使って、オンとオフを切り替えることができます。The style defined in cards.flip is toggled on and off in the flipCard function by using .toggleClass().

    $(card).toggleClass("flip");
    

    これにより、ユーザーがカードをクリックすると、カードは 180° 回転します。Now when a user clicks on a card, the card is rotated 180 degrees.

6。テストしてプレイする6. Test and play

これで終了です。Congratulations! Web アプリの作成が完了しました。You've finished creating the web app! ではテストを行いましょう。Let's test it.

  1. memory ディレクトリでコマンド プロンプトを開き、次のコマンドを入力します: npm startOpen a command prompt in your memory directory and enter the following command: npm start

  2. ブラウザーで https://localhost:3000/ に移動して、ゲームをプレイします。In your browser, go to https://localhost:3000/ and play a game!

  3. エラーが発生した場合は、キーボードで F5 キーを押して、Node.js と入力すると、Visual Studio Code の Node.js デバッグ ツールを使用できます。If you encounter any errors, you can use Visual Studio Code's Node.js debugging tools by pressing F5 on your keyboard and typing Node.js. Visual Studio Code でのデバッグについて詳しくは、この記事をご覧ください。For more information about debugging in Visual Studio Code, check out this article.

    コードを Final フォルダーに含まれているコードと比較することもできます。You can also compare your code to the code provided in the Final folder.

  4. ゲームを停止するには、コマンド プロンプトで次を入力します: Ctrl + CYTo stop the game, in the command prompt type: Ctrl + C, Y.

追加情報Going further

これで、作成したアプリを Azure (またはその他のクラウド ホスティング サービス) にデプロイして、モバイル、タブレット、デスクトップなどの、さまざまなフォーム ファクターのデバイスにわたってテストを行う準備ができました。You can now deploy your app to Azure (or any other cloud hosting service) for testing across different device form factors, such as mobile, tablet, and desktop. (さまざまなブラウザーでテストをすることを忘れないでください。)実稼働のための準備ができたら、ユニバーサル Windows プラットフォーム (UWP) のためのホストされた Web アプリ (HWA) として、容易にパッケージ化し、Microsoft Store から配布することができます。(Don't forgot to test across different browsers too!) Once your app is ready for production, you can easily package it as a Hosted Web App (HWA) for the Universal Windows Platform (UWP) and distribute it from the Microsoft Store.

Microsoft Store に公開するための基本的な手順は次のとおりです。The basic steps for publishing to the Microsoft Store are:

  1. Windows デベロッパー アカウントを作成します。Create a Windows Developer account
  2. アプリの申請のチェックリストを使用します。Use the app submission checklist
  3. アプリを申請して認定を受けます。Submit your app for certification

そのために役立つ追加情報を次に示します。Here are some useful resources for going further: