GUI開発チュートリアル
ここではSPAの開発とQmonus ApiFrontを用いたSPAホスティングについて解説します。
本章では下記をゴールイメージとしています。
Qmonus SDK LabからQmonus ApiFrontを用いてホスティングできるようになる。
- 簡易SPAの完成
- LabからApiFrontのデプロイ
- ローカルGUIとLabでデプロイした環境のAPI疎通
- E2E試験の作成
本チュートリアルはGUI開発経験のない方から対象としているため、ご自身の開発レベルに合わせて開発に必要な章をお読みください。
SPA開発経験者の方は3.[Qmonus SDK Lab]SPAのデプロイからの閲覧を推奨しています。
なお、本チュートリアル実行には
- GitHubの操作が可能なこと
- Qmonus SDK Labで環境デプロイが可能な設定が済んでいること
https://docs.sdk-lab.qmonus.net/guide-v3/guide4.html
が前提となります。Qmonus SDK Labの設定やアカウントについてはご自身のプロダクト管理者に問い合わせください。
用語の整理
以下、特に記述がない場合、Qmonus SDKのプロダクトは下記のように呼びます。
Lab
Qmonus SDK Labのこと。各開発環境を管理するプラットフォーム。
ドキュメント:https://docs.sdk-lab.qmonus.net/overview/top.html
SDK
Qmonus SDKの開発フレームワークのこと。ソフトウェア開発を実施するための機能を提供。
ドキュメント:https://docs.sdk.qmonus.net/
Portal
Qmonus SDK Portalのこと。SDKの開発用IDEの他、認証認可やモニタリングなど様々な機能を持つ総合開発環境。
ドキュメント:https://developer.qmonus.net/document/frontal/top
ApiFront
Qmonus ApiFrontのこと。SPAのホスティングやプロキシーなどFront周りの機能を持つ軽量Webサーバ。
ドキュメント:https://developer.qmonus.net/document/casval/top
FrontTester
Qmonus FrontTesterのこと。playwrightエンジンを搭載し、GUIのE2E試験をサポートする開発支援フレームワーク。
ドキュメント:https://developer.qmonus.net/document/edwow/top
1. [ローカル]セットアップ
ローカル環境でSPAの作成を行います。 SPAは各々の開発ツールを使っていただいて問題ありません。 今回は初学者向けに一例としてVueを使用します。
1-1. Vueのインストール
今回はnpmでグローバルにvueをインストールしています。
bash
$ npm install -g @vue/cli
Vueがインストールされているか確認します。今回は5.0.8で進めます。また、nodeは v18.13.0で開発しています。
bash
$ vue --version @vue/cli 5.0.8 $ node -v v18.13.0
1-2. プロジェクト作成
projectを作成します。GitHubにpushが可能な状態のディレクトリを使用ください。Vueは2系でも3系でも問題ありません。今回は3系にします。
$ vue create client Vue CLI v5.0.8 ? Please pick a preset: Default ([Vue 3] babel, eslint)
インストールが完了後、下記メッセージが確認できます。
bash
🎉 Successfully created project client.
👉 Get started with the following commands:
$ cd client
$ npm run serve
この時ディレクトリは下記の構成であればprojectの作成は成功です。

早速cdして起動してみましょう。
bash
$ cd client
$ npm run serve
> client@0.1.0 serve
> vue-cli-service serve
...
http://localhost:8080/
にアクセスして下記画面が見えれば、プロジェクトの起動は成功です。

Tips:
今回のチュートリアルで使用したパッケージのバージョンは下記になります。チュートリアル時に動作確認に失敗する場合、バージョンを合わせて実施してください。
json
./client/package.json
{
"name": "client",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@mdi/font": "5.9.55",
"axios": "^1.3.4",
"body-parser": "^1.20.2",
"core-js": "^3.8.3",
"http": "^0.0.1-security",
"roboto-fontface": "*",
"vue": "^3.2.13",
"vue-axios": "^3.5.2",
"vuetify": "^3.0.0-beta.0",
"vuex": "^4.0.2",
"webfontloader": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"vue-cli-plugin-vuetify": "~2.5.8",
"webpack-plugin-vuetify": "^2.0.0-alpha.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}
2. [ローカル]Vueでの開発
ここではSPAの開発について説明します。今回はApiFrontでのSPAホスティングの解説に注力しています。
そのため、Vueの実装はデプロイと動作確認が可能な最低限のものとし、実装の詳細などは省略しています。
また、本チュートリアルはVue2からの移植版のため、Vue3の最新の実装方式(composition API)を踏襲しておりませんのでご注意ください。
2-1. Vuetifyインストール
簡易にボタンを扱うため、Vuetifyをインストールします。今回は3系に合わせてインストールします。
bash
# ./client 配下
$ vue add vuetify
...
? Choose a preset: Vuetify 3 - Vue CLI (preview)
成功したら再度npm run serveしてください。
先ほどのVueの画面からVuetifyがインストールされている画面に変更されていればOKです。

2-2. axiosの追加
vueでAPIリクエストのためaxiosを使用します。下記を実行してください。
bash
# ./client/src配下
npm install --save axios vue-axios
インストール後、APIリクエスト処理用に client > src > plugins > api.jsを作成します。
./client/src/plugins/api.js
jsx
import axios from 'axios'
export const api = axios.create({})
export default {
install(app) {
app.config.globalProperties.$api = api
}
}
続いて、 client > src > main.jsを編集します。下記に置き換えてください。これでaxiosが実行可能になります。
./client/src/main.js
jsx
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
// axiosのインポート
import api from './plugins/api.js'
loadFonts()
createApp(App)
.use(vuetify)
// appに反映
.use(api)
.mount('#app')
2-3. ボタンの追加
3点を変更して、ボタン/ボタンが呼び出す関数/response用変数を用意します。
- 28行目以下にボタンを作るComponent配置
- ボタンを押した時に動く関数
getHealthCheck
定義 - responseの結果を格納する
res_data
を用意
ここではサンプルとして、地理情報を取得可能なAPIを叩いています。
./client/src/components/HelloWorld.vue
html
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12">
<v-img
:src="require('../assets/logo.svg')"
class="my-3"
contain
height="200"
/>
</v-col>
<v-col class="mb-4">
<h1 class="display-2 font-weight-bold mb-3">
Qmonus GUI開発チュートリアル
</h1>
<p class="subheading font-weight-regular">
チュートリアルの内容は下記を参照ください。
<br>
<a
href="https://developer.qmonus.net/document/casval/tutorial"
>Tutorial page</a>
</p>
</v-col>
</v-row>
<v-row class="text-center">
<v-col>
<v-btn @click=getHealthCheck()>GET HealthCheck</v-btn>
<p class="subheading font-weight-regular" v-show="Object.keys(res_data).length">
{{res_data}}
</p>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'TOP',
data: () => ({
res_data : {}
}),
methods: {
getHealthCheck: function () {
this.$api.get("https://geoapi.heartrails.com/api/json", {
params: {
method: "getPrefectures",
area: "関東"
}
})
.then(response => {
this.res_data = response.data
})
.catch(err => {
console.error(err)
})
}
}
}
</script>
GET HealthCheckボタンを押して下記のように出力されればOKです。

2-4. 静的ページのビルドとGitHubへのpush
以下のコマンドで静的ページをビルドします。
# ./client配下 npm run build
ビルドしたページはデフォルトでgitの追跡がされないため、 ./.gitignore に記載されている/dist
を消し、上記内容をGitにpushしてください。
3. [Qmonus SDK Lab]SPAのデプロイ
ここからはLabで環境をデプロイし、SPAのホスティングを行う部分について触れます。SPAのホスティングはApiFrontを用いて行います。
ApiFrontはSPAホスティングの他、認証やAPIプロキシーなどの機能を持つアプリケーションです。
詳細はApiFrontのドキュメントより閲覧可能です。
なお、繰り返しになりますが本章はLabでのApiFrontのデプロイに注力し、デプロイの細かいパラメータやその他マイクロサービスについては詳しく触れません。
Qmonus SDK Labでの環境作成手順と照らし合わせながら進んでいただければと思います。
3-1. BaseInfo
必要項目を入力ください。下記はサンプルになります。

3-2. Git Repositories
先ほどpushしたGitHubの情報を入力してください。

3-3. Secrets
不要です。
3-4. MicroServices
SDK / Portalは最新のバージョンを選びcheckしてください。今回両者はデプロイさえできれば良いので、それ以外の設定変更は不要です。
3-4-1. SDK

3-4-2. Portal

3-4-3. ApiFront
versionは最新ものを使用してください。以下を変更してください。
また、以降の手順より表記される [repository-name]
は使用しているリポジトリ名に置き換えてお読みください。
- settings > +content.baseのパラメータ変更
jsx
"+content.base" : "/var/plugins/[repository-name]/client/dist",
プロダクトの方針によっては、上記のLabでのbuild以外に2つのbuild方法があります。
- build機能を使用せずにローカルでビルドした資材をGitHubに上げて使用
- ApiFrontのアプリ内でのbuild
アプリ内でのビルドに関しては、こちらをご覧ください。
https://developer.qmonus.net/document/casval/boot-params
3-5. Check
上記手順完了後デプロイします。json内のQmonus-ApiFrontが下記のような設定になっていれば問題ありません。
json
{
"productName": "Qmonus-ApiFront",
"versions": {
"casval": "v23.1LTS-patch20230317",
"redis": "6.2-alpine"
},
"settings": {
"arguments": {
"+authentication.strategy": "qmonus",
"+backend.proxypath": "/apis",
"+backend.target": "http://apigw:9000",
"+recommendedMode": "true",
"+content.main": "index.html",
"+content.base": "/var/plugins/[repository-name]/client/dist"
},
"securityPolicy": "dev-api-policy",
"buildSettings": {
"pluginDir": "/var/plugins/[repository-name]/client"
}
}
}
3-6. デプロイの確認
ApiFrontが青く光っていれば完了です。クリックしてログインを行ってください。

作成したページが見えること、ボタン押下でレスポンスが見えればデプロイ完了です。

4. 起動パラメータの設定と反映
ApiFrontは起動パラメータという起動時にホスティングページの情報や認証、クッキー、APIプロキシーといった機能の設定を行うことができるパラメータを持ちます。
本手順では実際に起動パラメータを設定し、ページのtitle
とDiscription
を変更します。
カスタマイズできる各起動パラメータの詳細は、3.起動パラメータよりご確認ください。
起動パラメータの設定方法
Labからdev環境をデプロイする場合、起動パラメータの設定は2通りで行うことができます。
A. 起動パラメータをyaml形式で記述し、configファイルとして保存する
B. LabよりMicroServices > ApiFront > settings > argments
にprefix+を付けて追加する起動パラメータを記述
同様のパラメータに対して値を設定した場合、B.の設定が優先されます。
今回は上記の2パターンを両方設定し、優先されることを確認します。
A. 起動パラメータをyaml形式で記述し、configファイルとして保存する
4-1. configファイルの作成
早速デプロイ用のファイルをトップディレクトリに作成しましょう。
bash
# [repository-name]配下
$ touch config.dev.yml
4-2. 起動パラメータの記述
今回はtitleとmetaタグのdescriptionを変更します。cofig.dev.ymlに下記を記述してGitHubにpushしてください。
./config.dev.yml
yaml
# コンテンツ設定
content :
## title
title: "title ( set from yaml )"
## metaタグ設定
meta:
description: "description ( set from yaml )"
4-3. 既存設定の確認
Labでデプロイし直す前に既存の設定を確認します。
ApiFrontでデプロイしたSPAを開き、右クリックから「検証」を選択し、開発者ツールが開きます。
<head>
タグを展開するとtitleがclientであること、metaタグにdescriptionは存在しないことが確認できます。

4-4. Labによるconfigファイルの指定と環境更新
開発環境更新ボタンより環境更新を行います。今回変更が必要な点はMicroServices > ApiFront > settings > configPath
になります。
入力するにチェックを入れconfigpathにconfig.dev.ymlのpathを指定し、更新してください。
yaml
[repository-name]/config.dev.yml

4-5. パラメータ反映の確認
デプロイが完了したら、ページを開き反映されていることを確認します。
開発者ツールより確認すると、titleタグ、metaタグ descriptionタグが確認できます。

また、起動時に反映されたパラメータはPortalのCode editorを用いてログから確認できます。
terminalで下記コマンドを実行してください。
bash
$ less casval/log

デプロイの時刻に注意してログを探すと、下記のような起動時のパラメータ記述が見れると思います。
ここで、contentを確認すると、titleとmetaが反映されていることがわかります。
bash
2023-04-05 06:16:05.356 [ LOG ] version 23.1.1
2023-04-05 06:16:05.356 [ LOG ] ################## CASVAL BOOT FILE 1 ###################
2023-04-05 06:16:05.357 [ LOG ] ## Config File Path : /var/plugins/[repository-name]/config.dev.yml
2023-04-05 06:16:05.357 [ LOG ] ## Config Base Path : /var/plugins/[repository-name]
2023-04-05 06:16:05.357 [ LOG ] ################## CASVAL Overwrite Configs ###################
...(中略)...
2023-04-05 06:16:05.368 [ LOG ] !!! Overwrite Config Parameter! 'backend.proxypath': /apis
2023-04-05 06:16:05.369 [ LOG ] !!! Overwrite Config Parameter! 'backend.target': http://apigw:9000
2023-04-05 06:16:05.370 [ LOG ] !!! Overwrite Config Parameter! 'recommendedMode': true
2023-04-05 06:16:05.370 [ LOG ] !!! Overwrite Config Parameter! 'content.main': index.html
2023-04-05 06:16:05.370 [ LOG ] !!! Overwrite Config Parameter! 'content.base': /var/plugins/[repository-name]/client/dist
2023-04-05 06:16:05.370 [ LOG ] !! recommendedMode [true] , The mode follows the default behavior, so the behavior may change when updating the versi
on.
2023-04-05 06:16:05.371 [ LOG ] ################## CASVAL BOOT CONFIG ###################
2023-04-05 06:16:05.371 [ LOG ] {
"version": "23.1.1",
"appname": "Casval",
...(中略)...
"content": {
"enableHistory": true,
"securityPolicy": "self",
"securityPolicyOptions": {
"additionalScriptSrc": ""
},
"enableMultipage": false,
"isFrame": false,
"base": "/var/plugins/[repository-name]/client/dist",
"main": "index.html",
"delay": 0,
"build": {
"cwd": null,
"command": null,
"watch": {
"path": null
}
},
"title": "title ( set from yaml )",
"meta": {
"description": "description ( set from yaml )"
}
},
...(中略)...
B. settings>argmentsにprefix+を付けて追加する起動パラメータを記述する
4-6. 環境更新による起動パラメータ記述。
こちらは上記環境の環境更新を行うことで動作を確認します。
先ほどのconfigPathの設定はそのまま、ApiFront>settings>argumetns
に下記パラメータを追加します。
この設定でcontent.titleのパラメータを上書きが可能になります。
yaml
"+content.title": "title_Qmonus_SDK_Lab"

4-7. パラメータ反映の確認
titleが先ほど設定した値に変更されていることが確認できます。
また、configファイルで設定したmetaタグのdescriptionの存在も確認できます。

起動パラメータの優先順位が configファイル < Labの設定 であることが、上記titleの値でわかります。
共通の設定はconfigファイルで一括変更し、環境ごとに設定を変更したい場合はLabより設定することを推奨します。
4-8. staging環境以降のconfigファイルについて
staging以降は原則configファイルのみを用いて起動パラメータを管理する必要があります。
staging以降の起動パラメータの例はこちらにあります。
※ 一般の方は閲覧できません。チュートリアル実行には影響ありませんが、staging以降の起動パラメータについて不明点があればサポートまでお問い合わせください。
5. ローカルとQmonus SDK Labの疎通
ローカルからLabでデプロイしたdev環境のAPIを叩く実装を紹介します。
なお、ローカルとdev環境の疎通が不要な場合は本章の実行の必要はありません。
PortalのProxyを利用して実現します、リクエストのフローは下記になります。
- ローカルからdev環境のPortalにログイン
- Portal Proxy用pathを取得
- APIリクエスト実行
- Portal Proxy用pathをリクエストpathに追加
- リクエスト先をPortal(target)に変更
- 認証がある状態でPortalに対してリクエスト
- PortalがプロキシーしてSDKへリクエストをフォワード
- SDKのAPIに着弾
実現のため下記のステップを踏みます。
5-1. Portal疎通用の記述
5-2. GET /sessionの実行とsession情報及び環境情報の取得、保持
5-3. PortalProxy pathの追加
5-4. 動作確認
5-1. Portal疎通用の記述
5-1-1. qmonus-dev.jsの追加
qmonus-dev.jsを作成します。qmonus-dev.jsは2つの機能があります。
- Portalへのログイン
- /apisで指定されたリクエストをPortalへ転送
1.を用いてログインを行い、2.を用いてリクエストをPortalに転送します。
ここで指定している/apis
は5-3-1で取得するbackendのpathを参考にしています。
qmonus-dev.jsには下記の記述をしてください。
./client/qmonus-dev.js
jsx
/*************************************************************************
*
* Qmonus SDK ApiFront
* API proxy configuration tool for webpack
*
* version 1.1
*
* Copyright(C) 2015-2023 NTT Communications, Inc. All rights reserved
* author Yosuke Mizuno
*
*************************************************************************/
const axios = require('axios');
const https = require('https');
const bodyParser= require('body-parser')
const agent = new https.Agent({
rejectUnauthorized: false
});
const term = ( code , str )=>`\x1b[${code}m` + str + '\x1b[0m'
const logger = {
error: (msg) => console.error( `\n ${ term(41," FAIL ") } ${msg}` ),
done: (msg) => console.log( `\n ${ term(32," SUCCESS ") } ${msg}` ),
info: (msg) => console.info( `${ term(96," INFO ") } ${msg}` )
}
/**
* @param {*} target QmonusSDK-Portal endpoint
* @param {*} username Qmonus account username
* @param {*} password Qmonus account password
* @param {*} options proxy options
* @returns
*/
module.exports = ( { target , username , password , options={ headers:{} , inject:null } } )=>{
let Cookie = null; // Cached Cookie Value
target = target.replace(/\/*$/, "");
if (!(typeof options.inject))
delete options.inject;
return {
allowedHosts: "all",
async onAfterSetupMiddleware(devServer) {
devServer.app.use(bodyParser.json());
try {
let redirectRes = null;
try {
let params = new URLSearchParams();
params.append('username', username);
params.append('password', password);
redirectRes = await axios.post(`${target}/login`, params, {
httpsAgent: agent,
maxRedirects: 0
})
} catch (err) {
redirectRes = err.response;
}
if (redirectRes.status != 302)
throw new Error(`Login Redirect Fail , ${redirectRes.status} : ${redirectRes.statusText}`)
Cookie = redirectRes.headers['set-cookie'][0];
// login check
await axios.get(`${target}/session`, {
httpsAgent: agent,
maxRedirects: 0,
headers: {
'cookie': Cookie
}
})
} catch (ex) {
logger.error(`Qmonus Login Failed ${target} : [user:${username} , password:${password}]`)
console.error(ex.stack)
throw new Error("Qmonus Login Failed")
}
logger.done(`Qmonus Login successfully : Cookie ${Cookie}`)
// get session proxy
devServer.app.get("/session", async (req, res) => {
axios.get(`${target}/session`, {
httpsAgent: agent,
withCredentials: true,
headers: {
'cookie': Cookie
}
})
.then(ret => {
logger.info(`${target}/session : ${ret.data.account_id}(${ret.data.role_name})`)
res.json(ret.data)
})
.catch(ex => {
logger.error(`${target}/session : ${ex.message}`)
res.status(ex.response.status).json(ex.response.data)
})
})
// api proxy
devServer.app.all("/apis/*", (req, res) => {
let axiosParams = {
method: req.method,
url: `${target}${req.path}`,
headers: {
...req.headers,
...{
'cookie': Cookie
},
...(options.headers || {})
},
params: req.query,
data: req.body
};
if (options.inject)
axiosParams = {
...axiosParams,
...options.inject(axiosParams)
};
logger.info(`${ axiosParams.method } ${axiosParams.url} `)
console.debug(` headers : `, axiosParams.headers)
console.debug(` params : `, axiosParams.params)
if (axiosParams.method == "GET")
delete axiosParams.data;
else
console.debug(` data : `, axiosParams.data)
return axios({
...axiosParams,
httpsAgent: agent,
maxRedirects: 0,
withCredentials: true
})
.then(ret => {
logger.info(`${ axiosParams.method } ${axiosParams.url} >> ${ret.status} : [server:${ret.headers["server"]} , content:${ret.headers["content-type"]}]`)
res.status(ret.status)
Object.keys(ret.headers).forEach(function (k) {
switch (k.toLowerCase()) {
case "set-cookie":
case "cookie":
case "content-length":
break;
default:
res.set(k, ret.headers[k])
}
})
res.json(ret.data)
})
.catch(ex => {
logger.error(`${ axiosParams.method } ${axiosParams.url} >> ${ex.response.status} : [${ex.message}]`)
res.status(ex.response.status).json(ex.response.data)
})
})
}
}
}
5-1-2. dev環境にログイン用のアカウントを追加
Portalでのログイン用に事前にアカウントを作成しておいてください。
今回アカウントに紐付けるロールはlab_guest
としています。
SDK Portal / 4.API開発チュートリアル / Account Setting
5-1-3. vue.config.jsにdevServerの記述を追加
vue.config.jsを編集し、ローカル実行時にqmonu-dev.jsが起動するようにします。
また、編集例に含まれる以下の記述は作業環境に合わせて修正してください。
- {デプロイした環境のPortalのURL}
- {作成したアカウントのusername}
- {作成したアカウントのpassword}
./client/vue.config.js
jsx
const { defineConfig } = require('@vue/cli-service')
const qmonus = require("./qmonus-dev.js")({
target : "{デプロイした環境のPortalのURL}" ,
username : "{作成したアカウントのusername}" ,
password : "{作成したアカウントのpassword}",
})
module.exports = defineConfig({
transpileDependencies: true,
devServer : {
host: 'localhost',
port: 8080,
open: false,
...qmonus ,
},
pluginOptions: {
vuetify: {
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
}
}
})
5-2. session情報の取得
PortalやApiFrontに対して、GET /session
を実行することでユーザや環境の情報が取得可能です。
ApiFrontの/sessionのResponseは4.APIにあります。
今回はランディング前にPortalに対してGET /session
を実行し、Response BodyからPortalのプロキシー用のpath(session.backend)を取得します。
取得したプロキシー用のpathをstoreに保存し、pathをリクエスト時に追加する仕組みを実現します。
5-2-1. Vuexの導入
session情報の保持のためにVuexを導入し、store機能を使用可能にします。下記のコマンドを実行してください。
jsx
# ./client/src配下 npm install vuex@next
5-2-2. storeの記述を追加
main.jsにstoreのインポートを記述します。
./client/src/main.js
jsx
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
// axiosのインポート
import api from './plugins/api.js'
import { store } from './store/index.js'
loadFonts()
createApp(App)
.use(store)
.use(vuetify)
// appに反映
.use(api)
.mount('#app')
client > src > store > index.jsとなるようにフォルダとファイルを作成します。 今回はsessionの保存を記述します。
./client/src/store/index.js
jsx
import { createStore } from 'vuex'
export const store = createStore({
state: {
session: null,
},
getters:{
session(state){
return state.session || {}
}
},
mutations: {
session( state , session ){
state.session = session
}
},
actions: {
}
})
5-2-3. api.jsにgetSessionの追加
api.jsに/sessionを実行する関数getSessionを作成し、storeにresponseを保持します。
./client/src/plugins/api.js
jsx
import axios from 'axios'
import { store } from '../store/index.js'
export const api = axios.create({})
const getSession = async (reflesh=false)=>{
return new Promise((resolve,reject)=>{
const getSessionImpl = (retry)=>{
axios.get( `/session` , { params : retry ? { reflesh:true } : undefined } )
.then(res=>{
store.commit("session" , res.data )
resolve(res.data);
})
.catch(ex=>{
if( !retry )
return getSessionImpl(true)
store.commit("error" , ex )
reject(ex)
})
}
getSessionImpl(reflesh)
})
}
export default {
getSession : getSession ,
install(app) {
app.config.globalProperties.$api = api
}
}
5-2-4. main.jsの変更
main.jsにstoreとgetSessionを叩く記述を追加します。これによりランディング時にsessionが実行されます。
./client/src/main.js
jsx
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
// axiosのインポート
import api from './plugins/api.js'
import { store } from './store/index.js'
loadFonts()
;(async ()=>{
// Get session API
await api.getSession()
createApp(App)
.use(store)
.use(vuetify)
// appに反映
.use(api)
.mount('#app')
})();
5-3. PortalProxy pathの追加
5-3-1. api.jsにpath情報追加機能を記載
api.jsのapi.interceptors.request.use
にてconfig.baseURL
にsessionで取得したbackendのpath情報を追加するように変更します。
これによりリクエストpathにsessionで取得したpath情報が追加された状態でdevServerの処理に遷移します。
./client/src/plugins/api.js
jsx
import axios from 'axios'
import { store } from '../store/index.js'
export const api = axios.create({
})
api.interceptors.request.use(
(config) => {
// Portalの場合は/apis/axis/proxy
// ApiFrontの場合は/apis
config.baseURL = store.getters.session.backend;
return config
},
(error) => {
return Promise.reject(error)
}
)
api.interceptors.response.use(
(response) => {
return response
},
(error) => {
return Promise.reject(error)
}
)
const getSession = async (reflesh=false)=>{
return new Promise((resolve,reject)=>{
const getSessionImpl = (retry)=>{
axios.get( `/session` , { params : retry ? { reflesh:true } : undefined } )
.then(res=>{
store.commit("session" , res.data )
resolve(res.data);
})
.catch(ex=>{
if( !retry )
return getSessionImpl(true)
store.commit("error" , ex )
reject(ex)
})
}
getSessionImpl(reflesh)
})
}
export default {
getSession : getSession ,
install(app) {
app.config.globalProperties.$api = api
}
}
5-4. 動作確認
5-4-1. SDKへのAPIリクエスト
HelloWorld.vueにリクエストの内容を記述します。今回は環境で自動でデプロイされる監視用API、/healthcheck/ref/versions
に対してリクエストを実行します。
先ほどのgetHealthCheck
のpathとparamsを書き換えます。先ほどのconfig.baseURLのインジェクション機能のおかげで、ここでの記述は純粋なAPIpathである/healthcheck/ref/versions
とすることができています。
./client/src/components/HelloWorld.vue
html
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12">
<v-img
:src="require('../assets/logo.svg')"
class="my-3"
contain
height="200"
/>
</v-col>
<v-col class="mb-4">
<h1 class="display-2 font-weight-bold mb-3">
Qmonus GUI開発チュートリアル
</h1>
<p class="subheading font-weight-regular">
チュートリアルの内容は下記を参照ください。
<br>
<a
href="https://developer.qmonus.net/document/casval/tutorial"
>Tutorial page</a>
</p>
</v-col>
</v-row>
<v-row class="text-center">
<v-col>
<v-btn @click=getHealthCheck()>GET HealthCheck</v-btn>
<p class="subheading font-weight-regular" v-show="Object.keys(res_data).length">
{{res_data}}
</p>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'TOP',
data: () => ({
res_data : {}
}),
methods: {
getHealthCheck: function () {
this.$api.get("/healthcheck/ref/versions", {
})
.then(response => {
this.res_data = response.data
})
.catch(err => {
console.error(err)
})
}
}
}
</script>
5-4-2. 動作確認(ローカル)
この状態でnpm run serve
を実行してください。開発者ツールからGET /session
が200で帰っていることが確認できます。
また、ボタンを押下することでGET /healthcheck/ref/version
も200で帰り、bodyが出力できていることが確認できます。

5-4-3. 動作確認(dev環境)
npm run build
を実行した後、GitHubにpushしdev環境を更新してください。
ApiFrontでホスティングしたページでも同様にGET /session
とGET /healthcheck/ref/version
が200で帰っていることを確認できます。

図より、ApiFrontでホスティングしたページでは下記にリクエストを投げています。
GET /apis/healthcheck/ref/version
このAPIリクエストがSDKに着弾するのは、ApiFrontでのプロキシー機能を使用しているからです。
backend.proxypathで設定したpathのリクエストに対して、targetへリクエストをフォワードするdevServerと似た機能になります。
プロキシの設定は起動パラメータのbackendで指定可能であり、Labからデプロイ時はデフォルトで下記が埋め込まれています。
code editorより起動パラメータの値を確認すると下記になっていることが確認できます。
bash
..(中略)..
2023-04-10 07:22:16.780 [ LOG ] !!! Overwrite Config Parameter! 'backend.proxypath': /apis
2023-04-10 07:22:16.783 [ LOG ] !!! Overwrite Config Parameter! 'backend.target': http://apigw:9000
..(中略)..
"backend": {
"product": "axis",
"proxyTimeout": 60000,
"requestInjection": {
"delay": 0,
"script": null,
"headers": {}
},
"responseInjection": {
"delay": 0,
"script": null
},
"proxypath": "/apis",
"target": "http://apigw:9000"
},
..(中略)..
起動パラメータの詳細は3.起動パラメータより、API Proxyを参照ください。
6. FrontTesterを用いたGUI試験
GUI試験は納品物の品質保証の観点からも必須の試験となります。Qmonus SDKでは、結合試験、End to End(E2E)試験を見越したGUI試験ツールとしてFrontTesterを提供しています。
ここではFrontTesterを用いたGUI試験について紹介します。
6-1. FrontTesterについて
Qmonus FrontTesterはApiFront及びその他ブラウザに対して、ヘッドレスでGUIの単体試験を行うツールです。Portalから実行可能となっており、Qmonus SDKではFrontTesterを用いたGUI試験を推奨します。
下記は画面イメージです。試験の進捗やログ、スクリーンショットが確認可能なモニタリング画面と、コードの記述が可能なエディタが存在します。

詳細は Qmonus Documents / FrontTester /をご覧ください。
FrontTesterのメリットは
- APIリクエストで試験実行が可能であり、CIの利用や外部ツールからの試験実行が可能
- 試験パラメータと試験シナリオが分離されており、GUI単体試験からE2E試験、CIなど様々な用途に対応可能
- Portal上で実行・モニタリングが可能なため、Qmonus SDKを用いた一気通貫な開発が可能
が挙げられます。
今回作成したSPAを実際に試験するFrontTesterのチュートリアルを掲載しておりますので、実行いただくことを推奨します。