LoginSignup
0
0

More than 5 years have passed since last update.

Angular5 で俺式 KOAN スタック Webアプリ構築(4)

Last updated at Posted at 2018-03-21

クラサバ通信部の作成

  • 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 を以下の通りにする

middle/exchange/base/request.ts
/** 基底リクエスト */
interface IRequest {
    requestId: string;
}
export = IRequest;

response.ts を記述

middle/exchange/base/response.ts を以下の通りにする

middle/exchange/base/response.ts
/** 基底レスポンス */
interface IResponse {
    status: boolean;
    statusCode: number;
}
export = IResponse;

sample.request.ts を記述

middle/exchange/sample/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 を以下の通りにする

middle/exchange/sample/sample.response.ts
import Response = require('../base/response');

/** サンプル レスポンス */
interface ISampleResponse extends Response {
    result: number;
}
export = ISampleResponse;

サーバ側を対応

MiddlewareRouter を修正

server/middleware.router.ts を以下の通りに修正する

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 を以下の通りに修正する

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 を以下の通りに修正する

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 を以下の通りに修正する

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 を以下の通りに修正する

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 を以下の通りに修正する

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 を以下の通りに修正する

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ブラウザから叩くと使えます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0