このチュートリアルでは、ReactとAdonis Node.jsフレームワークを使って、Alibaba Cloud上でREST APIのバックエンドとフロントエンドを構築します。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
#序章
Adonisは、スケーラブルで安定した効率的なWebアプリケーションやREST APIを構築するために使用できるNode.jsフレームワークです。Reactを使用して、Adonisで構築されたREST APIを消費するためのモダンで堅牢なフロントエンドWebアプリケーションを構築します。
これから構築するWebアプリケーションは、MySQLのデータベースにイベントを格納し、これらのイベントを読み込んで削除します。
完成したら、以下のことができるようになります。
- Adonis.jsを使ったREST APIの構築
- Reactを使ってREST APIを消費する堅牢なクライアントサイドアプリケーションを構築する
- Bootstrap 4とReactを統合する
#前提条件
このガイドを始める前に、以下のものが必要です。
- Ubuntu 18.04を搭載したElastic Compute Service (ECS)開発マシン。
- Node.js 8.0.0.0+とNpm 3.0.0.0+がマシンにインストールされている。
- ローカルにインストールされたMySQL 5.7+。
#ステップ1 - Adonis APIプロジェクトの作成と依存関係のインストール
このステップでは、Adonisプロジェクトを足場にするのに役立つAdonis CLIをインストールし、アプリケーションのデータベース接続をセットアップするために必要な依存関係をインストールします。
ターミナルを開き、以下のコマンドを実行してAdonis.js CLIをグローバルにインストールします。
npm i -g @adonisjs/cli
これでインストールが完了したら、ターミナルのどこからでもadonis
を実行できるようになるはずです。以下のコマンドを実行して、インストールしたCLIのバージョンを確認することで試すことができます。
adonis --version
次に、新しいAdonisアプリケーションを足場にする必要があります。任意のディレクトリに移動し、以下のコマンドを実行します。
adonis new adonis-events --api-only
新しいコマンドは adonis-events
という新しいプロジェクトを足場にし、--api-only
は生成されたプロジェクトが特に REST API 用であることを指定します。新しいコマンドは、新しいプロジェクトに必要なすべての npm 依存関係をインストールします。
生成されるプロジェクトは以下のような構造になっているはずです。
次に、データベース接続を設定する必要があります。Adonis は多くの SQL データベースをサポートしていますが、使用する特定のデータベース、この場合は MySQL 用のパッケージをインストールする必要があります。プロジェクトフォルダに移動し、以下のコマンドを実行します。
npm i --save mysql
このプロジェクトでは、.env
というファイルにアプリケーションを設定するための環境変数が含まれています。データベース接続が mysql
に設定されていることを確認してください。
[~/adonis-events/.env]
...
DB_CONNECTION=mysql
...
最後に、このプロジェクトで使用する MySQL データベースをローカルに作成する必要があります。ローカルにMySQLがインストールされている場合は、以下のコマンドを実行してデータベースを作成します。
mysql -u root
mysql> CREATE DATABASE events;
新しいデータベースを作成したら、.env
ファイルの資格情報を作成したデータベースと一致するように更新します。
[~/adonis-events/.env]
...
DB_CONNECTION=mysql
DB_USERNAME=root
DB_DATABASE=events
DB_PASSWORD=
...
これが完了したら、REST APIとReactフロントエンドの作成に進みます。
#ステップ2 - Reactフロントエンドを作成する
このステップでは、Reactを使ってアプリケーションのフロントエンドを作成します。webpack の設定や本番のビルドプロセスを気にすることなく、React アプリケーションを素早く足場にするために、crease-react-app
という人気のあるパッケージを使用します。ローカルにcreate-react-app
がインストールされていない場合は、以下のコマンドを実行してください。
npm i -g create-react-app
インストールしたら、新しいフォルダに移動し、以下のコマンドを実行して新しいReactプロジェクトを作成します。
create-react-app adonis-events-react
新たに生成されたReactプロジェクトの構造は以下のようになります。
新しく作成したReactプロジェクトを起動するには、Reactプロジェクトディレクトリに移動し、以下のコマンドを実行します。
npm start
これにより開発サーバーが起動し、デフォルトのブラウザで以下のようなReactアプリケーションが開くはずです。
最後に、基本的なスタイリングを行うためのBootstrap CSSフレームワークをインストールしてみましょう。
Reactプロジェクト内のsrc
フォルダに入り、index.css
ファイルを開きます。このファイルの内容を以下のように置き換えます。
[~/adonis-events-react/src/index.css]
@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
上記は、ブートストラップCSSファイルへのリンクをインポートしたもので、フロントエンドプロジェクトのスタイルを素早く設定するために使用できるすべてのスタイルとクラスが含まれています。
フロントエンドアプリケーションのセットアップが完了したので、データベースモデルと移行を開発しましょう。
#ステップ3 - イベントの移行とモデルの作成
このステップでは、データベーステーブルをどのように構造化するかを決定する移行をセットアップし、このデータベーステーブルとの対話に役立つモデルをセットアップします。
まず、ターミナルでAdonisアプリケーションに移動し、次のコマンドを実行します。
adonis make:model Event -m
このコマンドは、モデルとそれに対応するマイグレーションを素早く作成する方法です。以下のような出力が得られます。
create app/Models/Event.js
create database/migrations/1541120387036_event_schema.js
作成したファイルは2つで、app/Models/Event.js
はこんな感じです。
'use strict'
const Model = use('Model')
class Event extends Model {
}
module.exports = Event
これは基本的なES6のクラスで、ベースとなるModel
クラスを継承しています。見ての通り、このクラスには多くの静的メソッドがあり、データベースと簡単にやりとりするのに役立ちます。
2つ目のファイルは、database/migrations/1541120387036_event_schema.js
で、以下のようになっています。
'use strict'
const Schema = use('Schema')
class EventSchema extends Schema {
up () {
this.create('events', (table) => {
table.increments()
table.timestamps()
})
}
down () {
this.drop('events')
}
}
module.exports = EventSchema
Adonisのマイグレーションは、ベースのSchema
クラスを拡張したES6クラスで、2つの重要なメソッドを含んでいます:up
は、データベーステーブルの作成や変更を含むデータベースへの変更を行うために使用され、down
はそれらの変更を反転させるために使用されます。up
関数では、データベーステーブルの構造を記述するAdonisが提供するメソッドを呼び出します。
現時点では、up
関数の中の関数this.create('events')がデータベース内にイベントテーブルを作成します。また、down
関数のthis.drop('events’)
は、必要に応じてデータベース内のイベントテーブルを削除します。
イベントテーブルには以下のフィールドがあります。
- title - イベントのタイトル
- start_date - イベントの開始日.
- end_date - イベントの終了日.
- location - 偶数の場所
- price - イベントの費用
マイグレーションでは、以下のようにこれらのフィールドを定義します。
次に、このマイグレーションファイルを実行して、Adonisが接続されたデータベースにこれらの変更を影響させることができるようにする必要があります。
プロジェクトフォルダにあることを確認し、以下のコマンドを実行してください。
adonis migration:run
以下のような出力が表示されるはずです。
migrate: 1503250034279_user.js
migrate: 1503250034280_token.js
migrate: 1541120387036_event_schema.js
Database migrated successfully in 206 ms
このコマンドを実行すると、Adonisは各マイグレーションファイルを読み込み、これらのファイル内でup
機能を実行します。したがって、現時点では、私たちのデータベースには、users
、tokens
、events
の3つのテーブルが新たに作成されています。最初の2つのテーブルは、Adonisの新規インストール時にデフォルトで出荷されます。
データベースのセットアップが完了したら、REST APIの作成に進みます。
#ステップ4 - REST APIの作成
このステップでは、REST APIを作成します。イベントに対するさまざまなアクションを処理するために、いくつかの API エンドポイントを作成します。作成するエンドポイントは以下の通りです。
-
[POST] /api/events
は、イベントを作成 -
[DELETE] /api/events/:id
は、 特定のイベントを削除 -
[GET] /api/events
は、すべてのイベントのリストを取得
####[POST]/api/eventsエンドポイントの実装
まずは、これらのエンドポイントを処理するためのコントローラを生成することから始めましょう。コントローラは基本的に ES6 クラスで、すべてのビジネスロジックを処理するメソッドを含んでいます。以下のコマンドを実行してください。
adonis make:controller EventController
以下のような出力が表示されるはずです。
> Select controller type For HTTP requests
create app/Controllers/Http/EventController.js
次に、この特定のエンドポイントを扱うルートを登録する必要があります。start/routes.js
ファイルを開き、以下を追加します。
Route
クラスにはpost
という静的関数があり、このメソッドはpostエンドポイントを登録します。最初のパラメータはパス、api/events
、2番目のパラメータはこのエンドポイントへのリクエストを処理するコントローラとメソッドです。この場合、EventController
の store
メソッドです。つまり、このメソッドを作成する必要があります。EventController
のように追加します。
Adonis は context
と呼ばれるオブジェクトを注入しますが、この context
には request
オブジェクトと response
オブジェクトを含む、requestに関する多くの関数とオブジェクトが含まれており、request
オブジェクトにはrequestに関するすべての情報が含まれています。現時点でのstore
メソッドでは、request.all()
関数を呼び出すと、POSTリクエストで送信された全てのデータを返してくれます。今回は、イベントを作成するために、リクエストデータにtitle、start_date、end_date、location、price
が提供されていることを想定しています。
次に、このデータをデータベースに保存しなければなりません。データベース、特にevents
テーブルと通信するために、モデルを使用します。events
モデルを使用すると、Adonisは自動的にevents
テーブルに接続します。
events
モデルを使用して、create
関数を呼び出しました。これは、POSTリクエストから取得したデータを使用して、自動的に新しい行をeventsデータベーステーブルに保存します。この関数は新しく作成されたイベントを返し、このeventsと一緒にJSONレスポンスを返します。
注: Adonisのuse
関数はNode.jsのrequire
関数のラッパーです。これは名前空間を使用し、上で行ったようにファイルを簡単にrequireするのに役立ちます。ですから、require('../.../.../Models/Event.js’)
の代わりに、単に use('App/Models/Event')
と書きます。
先ほど実装した/POSTエンドポイントを試してみましょう。そのためには、Adonis APIを実行する必要があります。
以下のコマンドでadonisサーバーを実行します。
adonis serve --dev
info: serving app on http://127.0.0.1:3333
新しく作成したPOST /api/events
エンドポイントを試すために、任意のRESTクライアントを使用することができます。今回はPOSTMANを使ってみます。
操作結果は以下の通りです。
注:POSTMANではContent-type
をapplication/json
に設定することを忘れないでください。
####[取得] api/eventsエンドポイントの実装
このエンドポイントのルートを追加してみましょう。routes.js
ファイルで、次のように追加します。
[~/adonis-events/start/routes.js]
Route.get(api/events', 'EventController.index')
これはエンドポイントを EventController
の index
メソッドにマッピングします。このコントローラでは、次のように追加してみましょう。
index
メソッドは、events
モデルのall()
関数を使用してevents
テーブルからデータベースのすべての行を取得します。これをPOSTMANで試してみると、以下のような結果が得られるはずです。
####[削除] api/events/:id エンドポイントの実装
最後に実装しなければならないエンドポイントは、イベントを削除するためのものです。このエンドポイントはこれまでの他のエンドポイントとは少し異なり、動的パラメータを使用します。このエンドポイントのルートを登録してみましょう。
[~/adonis-events/start/routes.js]
Route.delete(api/events/:id', 'EventController.delete')
ルートの :id
は動的パラメータで、削除したいイベントの特定の id
を渡すことができます。このルートを EventController
の delete
メソッドにマッチさせます。
delete
メソッドでは、ルートから取得した動的 ID
を使用してイベントを検出し、検出されたイベントに対して delete
関数を呼び出します。以下に POSTMAN でのテストの様子を示します。
それだけです。Adonisで完全に機能するAPIを作るのはこんなに簡単なことなのです。フロントエンドに切り替える前にもう一つ。現時点では、Adonis APIは他のサーバーやドメインからのリクエストを許可しません。これはCORS保護と呼ばれるもので、不正なリクエストがAPIに行われないようにするために本当に重要です。この特定のケースでは、ReactフロントエンドがAPIリクエストを行うことを許可するようにAdonisに指示しなければなりません。これを行うには、Adonisには設定ファイルが既に設定されているので、アプリケーションのCORS設定を変更することができます。config/cors.js
に移動して、このファイルをこのように修正します。
[~/adonis-events/config/cors.js]
origin: ['http://localhost:3000'],
ここでは、すべての認可されたオリジンの配列を作成し、この配列にリストされたすべてのドメインがAdonisアプリケーションにAPIリクエストを行うことができるようになります。クライアント側のReact開発サーバーのドメインは http://localhost:300
なので、これをorigin
配列に追加しました。
次のステップでは、Reactフロントエンドに切り替えて、堅牢なクライアントサイドアプリケーションを構築するために、このデータの消費を開始しましょう。
#ステップ5 - クライアントサイドコンポーネントを設定する
最初に設定するコンポーネントは、App
コンポーネントです。これは、最初にアプリケーションにアクセスしたときに表示されるコンポーネントです。他の不要なファイルもすべてクリーンアップします。
不要なファイルを削除した後の現在のフォルダ構造は以下の通りです。
次に、単一のイベントを表現するために使用するコンポーネントを作成してみましょう。プロジェクトフォルダに移動し、src
フォルダ内にEvent.js
というファイルを作成します。
このコンポーネントは、現時点での静的データを表示し、単一のイベントを表示するためのテンプレートを表しています。
最後に、AddEvent.js
という別のファイルを作成します。これは、新しいイベントを追加するためのフォームとして機能します。
必要なコンポーネントの作成が完了したので、APIサービスを作成してみましょう。
#ステップ6 - Axios APIサービスの作成
Adonis API と通信できるようにするために、シンプルな HTTP クライアントを使用します。このクライアントをインストールするには、Reactプロジェクトに移動し、次のコマンドを実行します。
npm install axios --save
これをインストールしたら、src
フォルダに apiService.js
というファイルを作成し、以下のクラスを追加します。
このクラスは axios のシンプルなラッパーであり、Adonis API への HTTP リクエストを行うためのヘルパー関数を提供します。コンストラクタでは、すべてのリクエストのBaseURL
をAdonisアプリケーションのURLに設定します。
サービスの準備ができたので、これらのコンポーネントを機能させてみましょう。
#ステップ7 - イベントの作成
イベントを作成するために、Create Event
ボタンを用意します。ユーザーがこのボタンをクリックすると、イベントを作成するためのフォームを持つコンポーネントが表示されます。Appコンポーネントを以下のように変更してみましょう。
現時点では以下のようになっています。
まず、AddEvent
コンポーネントをインポートしました。showCreateEventForm
というステート・プロパティを設定し、レンダー関数の中で、このプロパティが真であればAddEvent
コンポーネントをマウントし、そうでなければマウントしません。Create Event
ボタンがクリックされると、このステート・プロパティの値を切り替えます。また、showCreateEventForm
が true
の場合は Create Event
ボタンに btn-danger
クラスを動的に追加し、このプロパティが false
の場合は btn-info
を追加します。
次のステップは、このフォームを実際に動作させて、ユーザーがイベントの詳細を入力して保存できるようにすることです。
####イベントの作成機能の実装
最初のステップは、ユーザーが入力した入力を取得することです。これを管理するためにステートを使います。ここにAddEvent.js
コンポーネントのアップデート版があります。
この時点では、入力フィールドが変更されるたびに、その値は自動的にこのコンポーネントの状態に設定されます。
現時点では、デフォルトのブラウザの日付ピッカーを使用しており、これには時間ピッカーが統合されていません。さらに、この日付ピッカーの動作はブラウザによって非常に一貫性がありません。そこで、start_date
とend_date
のフィールドには、FlatPickr
と呼ばれるサードパーティ製の日付ピッカーを使用します。この日付ピッカーをインストールするには、以下のコマンドを実行します。
npm i --save react-flatpickr
インストールできたら、このようにフォームを修正してみましょう。
まず、インストールしたFlatPickr
コンポーネントをインポートします。前回の日付入力の代わりに、FlatPickr
をマウントし、handleDateChange
と呼ばれる別のハンドラを渡します。これはほとんど同じことを行い、start_date
とend_date
の値が変更されたときの状態に設定します。
さて、このイベントを保存するためのAPIリクエストを実際に行う時が来ました。これを行うために、Appコンポーネントから関数を渡し、呼び出されたときにイベントを保存します。Appコンポーネントをこのように修正してみましょう。
コンポーネントをこのように更新してみましょう。
まず、ApiService
をインポートし、Appコンポーネントのコンストラクタで新しいインスタンスを作成します。次に、apiServiceからの関数であるstoreEvent
というAddEvent
コンポーネントにプロップを渡します。
次に、AddEvent
コンポーネントのCreate Event
ボタンが作成された際に、このプロップを呼び出す必要があります。
Create Event
ボタンがクリックされると、this.props.storeEvent()
を呼び出し、状態をパラメータとして渡します。この関数は axios を呼び出し、イベントを保存するための HTTP リクエストを行います。開発者ツールで発信HTTPリクエストを確認すると、AdonisサーバーからのHTTPレスポンスが表示されているはずです。
すべてのイベントのリストが表示されるまでは、作成されたことを確信することはできませんよね?次のステップでは、Adonis APIからすべてのイベントのリストをフェッチして表示します。
####すべてのイベントをフェッチして表示する
すべてのイベントを取得するために、コンポーネントがマウントされた直後に [GET]
リクエストを行い、結果を取得したら、その結果をステートに設定してコンポーネントに表示します。これを実現するために、componentDidMount
というReactのライフサイクルフックを追加してみましょう。この関数は、コンポーネントがマウントされるとすぐに実行されます。
まず、イベントという新しいステートプロパティを空の配列に設定します。次に、componentDidMount
関数の中で、APIリクエストをしてすべてのイベントを取得し、レスポンスが返ってきたら、その結果をstateに設定します。この時点でReact Dev toolsなどのツールを使ってコンポーネントの状態を検査すると、すべてのイベントのリストが表示されているはずです。
次のステップは、このイベントのリストをコンポーネントに表示することです。このために作成したEvent
コンポーネントを使用します。App
コンポーネントをこのように変更してみましょう。
各イベントをマッピングして、1つのイベントを所定の場所に表示します。現時点では、アプリケーションがマウントされると、対応するイベントのリストが表示されるはずです。
イベント コンポーネントはまだ動的ではありません。これは、特定のイベント(Appコンポーネントから渡された)のためのプロップを受け取り、代わりにそれらを表示する必要があります。この動作をサポートするように変更してみましょう。
これで、各イベントはevent
プロップを介して渡されたカスタムデータを表示するようになりました。
現時点では、イベントを作成しても何も起こりません。より良いエクスペリエンスを得るために、App コンポーネントを修正して、AddEvent
フォームを非表示にし、すべてのイベントを再度取得して、ユーザーが新しく作成されたイベントを見ることができるようにします。
最初に、fetchEvents
という新しい関数を作成します。次に、storeEventという新しい関数を作成します。この関数はAPIを呼び出して新しいイベントを保存し、レスポンスを取得したらfetchEvents
を呼び出してすべてのイベントを取得し、toggleShowCreateEventForm
を呼び出してcreateイベントフォームを非表示にします。
#ステップ8 - Deleteイベントの実装
最後のタスクは、イベントを削除できるようにすることです。App コンポーネント上でイベントを削除する関数を作成し、この関数をEvent
コンポーネントのプロップとして渡し、ユーザーが削除ボタンをクリックするたびにこの関数が呼び出されます。Appコンポーネントは次のようになります。
新しく追加された関数deleteEvent
はAPIサービスを呼び出し、イベントが削除されると、再びfetchEvents
を呼び出して、すべてのイベントの新鮮なコピーを取得します。最後に、Event
コンポーネントで、id
パラメータを指定してこの関数を呼び出します。このようにEvent
コンポーネントを修正します。
すべての変更を行った後のプロジェクトの動作は次のようになります。
このアプリケーションが完成したことで、実際のプロジェクトの参考として使用できる最新のフルスタックJavascriptアプリケーションの基礎を手に入れることができます。
#結論
このチュートリアルでは、Adonis.jsとReact.jsを使ってフルスタックのJavascriptデモアプリケーションを作成しました。REST APIの構築にはAdonis.js、APIの消費にはReact、アプリケーションのスタイリングにはBootstrap 4を使用しました。Adonis REST APIのソースコードはこちらのGitHubリポジトリに、ReactフロントエンドアプリケーションのソースコードはこちらのGitHubリポジトリにあります。
Adonisフレームワークについてもっと詳しく知りたい場合は、公式ドキュメントがとても便利で、ビデオチュートリアルも提供されています。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ