クラサバ通信部の作成
- Angular5で「俺式KOANスタック」でWebアプリ構築するための個人的な備忘録記事。
- 概要については「こちら」を参照。
- 事前に「バックエンド初期設定」が完了していることが前提。
- 本記事まで完了すればWebアプリとして最低限の動作が可能
中間部分を作成
クライアントとサーバでやり取りするインターフェースや、どちら側でも使用できる様なモジュール領域を定義します。
普通はそんな構成にしないかもしれませんが、その辺は「俺式KOANスタック」ということで。
フォルダ および ファイル を追加
- ルートディレクトリ直下に
middle
フォルダを作成し、配下にexchange
,base
,sample
新規に空のファイルrequest.ts
,response.ts
,sample.request.ts
,sample.response.ts
を作成して以下のような構成にする
middle
└─ exchange
├─ base
│ ├─ request.ts
│ └─ response.ts
│
└─ sample
├─ sample.request.ts
└─ sample.response.ts
request.ts を記述
middle/exchange/base/request.ts
を以下の通りにする
/** 基底リクエスト */
interface IRequest {
requestId: string;
}
export = IRequest;
response.ts を記述
middle/exchange/base/response.ts
を以下の通りにする
/** 基底レスポンス */
interface IResponse {
status: boolean;
statusCode: number;
}
export = IResponse;
sample.request.ts を記述
middle/exchange/sample/sample.request.ts
を以下の通りにする
import Request = require('../base/request');
/** サンプル リクエスト */
interface ISampleRequest extends Request {
num1: number;
num2: number;
}
export = ISampleRequest;
sample.response.ts を記述
middle/exchange/sample/sample.response.ts
を以下の通りにする
import Response = require('../base/response');
/** サンプル レスポンス */
interface ISampleResponse extends Response {
result: number;
}
export = ISampleResponse;
サーバ側を対応
MiddlewareRouter を修正
server/middleware.router.ts
を以下の通りに修正する
import KoaRouter = require('koa-router');
import Request = require('../middle/exchange/base/request');
import Response = require('../middle/exchange/base/response');
import SampleContoroller = require('./app/controller/sample.controller');
/** ミドルウェア ルータ */
class MiddlewareRouter {
/** 各ルータを束ねたミドルウェアを生成 */
public routes(): KoaRouter.IMiddleware {
const koaRouter = new KoaRouter();
koaRouter.get('/api/get-sample', this.callGet(new SampleContoroller().test));
koaRouter.post('/api/post-sample', this.callPost(new SampleContoroller().test));
return koaRouter.routes();
}
/**
* 実行処理の呼び出し(GET)
* @param controll 実行される処理
* @returns ルータに設定するミドルウェア
*/
private callGet(controll: (request: Request) => Promise<Response>): any {
return async function(ctx: KoaRouter.IRouterContext) {
const ctxRequest: any = ctx.request;
const ctxResponse = await controll(ctxRequest.query);
ctx.body = ctxResponse;
};
}
/**
* 実行処理の呼び出し(POST)
* @param controll 実行される処理
* @returns ルータに設定するミドルウェア
*/
private callPost(controll: (request: Request) => Promise<Response>): any {
return async function(ctx: KoaRouter.IRouterContext) {
const ctxRequest: any = ctx.request;
const ctxResponse = await controll(ctxRequest.body);
ctx.body = ctxResponse;
};
}
}
export = MiddlewareRouter;
ルート「/」へのGETリクエストメソッドを削除
ベタ書きのインターフェースを削除し、作成したインターフェースを利用するように変更
POSTリクエストの処理を追加
SampleController を修正
server/app/controller/sample.controller.ts
を以下の通りに修正する
import SampleRequest = require('../../../middle/exchange/sample/sample.request');
import SampleResponse = require('../../../middle/exchange/sample/sample.response');
/** サンプル コントローラ */
class SampleContoroller {
public async test(request: SampleRequest): Promise<SampleResponse> {
console.log('=== SampleContoroller # test ===');
console.log(request);
return await {
status: true,
statusCode: 200,
result: 1
} as SampleResponse;
}
}
export = SampleContoroller;
「any」型のインターフェースをやめ、作成したインターフェースを利用するように変更
server.ts を修正
server/server.ts
を以下の通りに修正する
// アプリケーションサーバ起動設定
import Koa = require('koa');
import path = require('path');
import koaStatic = require('koa-static');
import bodyparser = require('koa-bodyparser');
import MiddlewareRouter = require('./middleware.router');
const app = new Koa();
// サーバ側ミドルウェアの提供
app.use(bodyparser({
extendTypes: {
json: ['application/x-javascript']
}
}))
.use(new MiddlewareRouter().routes());
// クライアント側ミドルウェアの提供
app.use(koaStatic(path.resolve(process.cwd(), './dist/client')));
// サービス開始
const port = 3000;
app.listen(port, () => console.log(`App is listing port in ${port}`));
クライアント側ミドルウェアの提供処理を追加
フロントエンド側を対応
sample.service.ts を修正
client/app/services/sample.service.ts
を以下の通りに修正する
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import 'rxjs/add/operator/toPromise';
import SampleRequest = require('../../../../middle/exchange/sample/sample.request');
import SampleResponse = require('../../../../middle/exchange/sample/sample.response');
@Injectable()
export class SampleService {
constructor(private http: HttpClient) { }
/** GET通信 サンプル */
public async getReq(): Promise<any> {
// GETリクエスト作成
const httpHeaders: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
let httpParams: HttpParams = new HttpParams();
httpParams = httpParams.append('testKey', 'aaaaa');
httpParams = httpParams.append('otherKey', 'bbbbb');
httpParams = httpParams.append('testKey', 'ccccc');
// GETリクエスト送信
return await this.http.get<SampleResponse>('/api/get-sample', {
headers: httpHeaders,
params: httpParams
}).toPromise();
}
/** POST通信 サンプル */
public async postReq(): Promise<any> {
// POSTリクエスト作成
const httpHeaders: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
const body = {
num1: 7,
num2: 9
} as SampleRequest;
// POSTリクエスト送信
return await this.http.post<SampleResponse>('/api/post-sample', body, {
headers: httpHeaders
}).toPromise();
}
}
GET/POSTリクエスト通信を非同期で行うように変更
コンポーネント修正
sample.module.ts 修正
client/app/components/sample.module.ts
を以下の通りに修正する
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { SampleComponent } from './sample.component';
import { SampleServiceModule } from '../../services/sample/sample-service.module';
/**
* サンプル コンポーネントモジュール
*/
@NgModule({
imports: [
CommonModule,
RouterModule,
FormsModule,
SampleServiceModule
],
declarations: [
SampleComponent,
],
exports: [
SampleComponent
]
})
export class SampleModule {}
修正したサービスのモジュールをインポート
sample.component.ts 修正
client/app/components/sample.component.ts
を以下の通りに修正する
import { async } from '@angular/core/testing';
import { Component, OnInit } from '@angular/core';
import { SampleService } from '../../services/sample/sample.service';
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.css']
})
export class SampleComponent implements OnInit {
constructor(private service: SampleService) { }
ngOnInit() {
}
/** TEST GET ボタン押下時 */
async testGetBtn(): Promise<void> {
const res = await this.service.getReq();
console.log('\n=== res ===');
console.log(res);
}
/** TEST POST ボタン押下時 */
async testPostBtn(): Promise<void> {
const res = await this.service.postReq();
console.log('\n=== res ===');
console.log(res);
}
}
作成したGET/POSTリクエストのサービスを呼ぶように変更
sample.component.html 修正
client/app/components/sample.component.html
を以下の通りに修正する
<div>
sample works!
<button (click)="testGetBtn()">TEST GET</button>
<button (click)="testPostBtn()">TEST POST</button>
</div>
GET/POSTリクエストのサービスを呼ぶボタンを追加
クラサバ通信確認
動作確認 (ts-node起動)
-
npm run start
でサーバ(server.ts)を起動し、コンソール上に「App is listing port in 3000
」と表示されたら、Webブラウザでhttp://localhost:3000/#/sample-page
にアクセスし、Webブラウザの開発者モード(ChromeならF12など)を起動し、ブラウザコンソールを表示する。 - 画面最下部の「TEST GET」ボタンを押下し、ブラウザコンソールに「
{status: true, statusCode: 200, result: 1}
」と表示され、かつ、コンソール上に以下のとおりにレスポンスが表示されたら成功。
=== SampleContoroller # test ===
{ testKey: [ 'aaaaa', 'ccccc' ], otherKey: 'bbbbb' }
- 画面最下部の「TEST POST」ボタンを押下し、ブラウザコンソールに「
{status: true, statusCode: 200, result: 1}
」と表示され、かつ、コンソール上に以下のとおりにレスポンスが表示されたら成功。
=== SampleContoroller # test ===
{ num1: 7, num2: 9 }
- 動作確認できたら
Ctrl + C
でサーバ終了。
動作確認 (node起動)
- 事前に「
dist
」フォルダを削除し、コンソール上でnpm run build
コマンドでビルドを実行し、dist フォルダ配下に「client」「middle」「server」フォルダと配下のファイルが生成されていたら準備完了。 -
node dist/server/server.js
でコンパイルされたサーバ(server.ts)を起動し、コンソール上に「App is listing port in 3000
」と表示されたら、Webブラウザでhttp://localhost:3000/#/sample-page
にアクセスし、Webブラウザの開発者モード(ChromeならF12など)を起動し、ブラウザコンソールを表示する。 - 画面最下部の「TEST GET」ボタンを押下し、ブラウザコンソールに「
{status: true, statusCode: 200, result: 1}
」と表示され、かつ、コンソール上に以下のとおりにレスポンスが表示されたら成功。
=== SampleContoroller # test ===
{ testKey: [ 'aaaaa', 'ccccc' ], otherKey: 'bbbbb' }
- 画面最下部の「TEST POST」ボタンを押下し、ブラウザコンソールに「
{status: true, statusCode: 200, result: 1}
」と表示され、かつ、コンソール上に以下のとおりにレスポンスが表示されたら成功。
=== SampleContoroller # test ===
{ num1: 7, num2: 9 }
- 動作確認できたら
Ctrl + C
でサーバ終了。
ここまでが クラサバ間の通信部分を構築。
これで、Webアプリとして最低限の動作が可能なので、どっかのサーバにおいてWebブラウザから叩くと使えます。