- 投稿日:2019-08-27T22:28:54+09:00
Alexa APL, 第14回 フッターの追加
はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
今回は、フッターを追加します。
フッターは、レスポンシブ対応コンポーネントと呼ばれ、コンポーネントをまとめて使いやすくしたモジュールのようなものです。
フッターと聞くと、Copyrightやページ番号など入るスペースのイメージなのですが、Alexaのフッターはそうではなく、ユーザーへのアクションを補助するためのヒント(例えば、「〇〇といってください。」というヒント)を表示するためのものです。今回実施する内容
AlexaFooterを使って、フッターを追加する。
環境
OS:Windows 10 JP
Alexaスキル言語:Node.js
Editor:Visual Studio Code
APLバージョン:1.0, 1.1参考
・Alexa ハローAPL、Alexaスキルの画面への対応
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。・Alexa APL, 第5回 ヘッダーの追加
第5回のAlexa APLの記事です。AlexaHeaderを使ってヘッダーを追加する記事です。・Alexa APL, 第8回 タッチ対応 その2(SpeakItem)
第8回のAlexa APLの記事です。タッチ対応の記事ですが、トランスフォーマーの記載をしています。・APLデータソースとトランスフォーマー
ヒントに「アレクサ」といった正しい「ウェイクワード」を追加する仕組みの説明があります。用語
APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている
・「Alexa ハローAPL、Alexaスキルの画面への対応」、および「AAlexa APL, 第5回 ヘッダーの追加」の記事をみているフッターを追加してみる
画面の下にフッターを追加します。
フッターだからと言って、画面の下である必要性はないのですが。「alexa-layouts」パッケージの読み込み
フッターを追加するには、「alexa-layouts」パッケージを読み込む必要があります。
まずはAPLオーサリングツールを起動し、「最初から作成」を選択する。
APLオーサリングツールでは、「Document」ボタンを押すと、JSONが表示されますが、「"import"」は空です。そこに以下を書き込みます。APL... "import": [ { "name": "alexa-layouts", "version" : "1.0.0" } ], ...これを記載するだけで、「Container」、「Text」などと同じようにAPLオーサリングツールで、フッター(AlexaFooter)のコンポーネントを使えるようになります。
この記載は、alexa-layoutsパッケージを読み込んで、このAPLで利用するという意味であり、versionも更新されていきます。APL 1.0ではalexa-layoutsパッケージのversionは1.0.0だったのですが、APL 1.1では1.1.0に更新されました。現時点では、APLオーサリングツールは、APL 1.1には完全には対応していないようで、APL 1.1で追加されたプロパティは設定できません。しかし、APL画面で自分で直接JSONコードを記載すればAPLオーサリングツールの画面レイアウトイメージは更新されます。
「AlexaHeader」、「AlexaFooter」は、他のコンポーネントと違い、「APLコンポーネント」を継承しないため、「when」とか「width」など使えないような気がします。
APLオーサリングツールにテンプレートが用意されていますが、その中での「AlexaFooter」の使い方をみてみると、「Container」で利用可能なプロパティである
- top
- position
などが使われていました。上位に親Containerが存在すれば、子Containerのプロパティは設定可能と理解しました。レイアウトの作成
- APLオーサリングツールを起動して「最初から作成」を選択する。(上記で実施済み)
- 「レイアウト画面」の「mainTemplate」を選択し、「Container」を追加する。 「レイアウト画面」で、「Container」を選択し、「AlexaFooter」を追加する。
「レイアウト画面」の「AlexaFooter」を選択し、「詳細設定画面」で、以下をそれぞれ設定する。
・ hintText:${payload.sample.properties.hintText}
「APL JSON」ボタンを押して、「AlexaFooter」に以下のプロパティを追加する。
・ top:85vh
・ position:absoluteデータJSONの作成
続いてデータJSONを以下の通り作成する。
上記のレイアウト作成では、FooterのプロパティのhintTextに変数で設定しました。この部分の元データを作成します。
これは、textToHintトランスフォーマーを使って、ヒントに「ウェイクワード」を追加するために変数化しています。
説明は、次の章でまとめて説明します。APL{ "sample": { "properties" : { "hintText" : "ヒント" }, "transformers": [ { "inputPath": "hintText", "transformer": "textToHint" } ] } }以下のような画面がAPLオーサリングツールで表示されました。
なお、実機のEcho Show 5では、
「"Alexa, ヒント"と言ってください」
と表示されました。
ウェイクワードを「Amazon」に変更すると、上記の「Alexa」部分が「Amazon」に変わることを確認しました。
textToHintトランスフォーマーの補足
第8回のタッチ操作の時に説明したssmlToSpeechトランスフォーマーと実施する方法は同じです。
textTohintトランスフォーマーは、入力した文字列「〇〇」に対して、「"アレクサ、〇〇"と言ってみてください」のように、ウェイクワードと、「と言ってみてください」を追加します。
ウェイクワードの変数だけならばまだ他の機能で使い用がありそうですが、「と言ってみてください」までついてくると、ほとんどAlexaFooter専用のトランスフォーマーだなという印象です。
利用可能なプロパティについて(alexa-layouts 1.1.0)
AlexaFooterで利用可能なプロパティは、alexa-layoutsの1.1.0になると以下です。
プロパティ名 説明 追加されたバージョン hintText フッターに記載するヒントの文字列。 1.0.0 theme 設定するテーマ。デフォルトはdark。 1.1.0 type AlexaFooter 1.0.0 試しに、alexa-layoutsを1.1.0にして、
themeをlightに設定したところ、文字は黒字になることを確認しました。APLソースコード
今回試したソースコードを載せます。実際にスキルで表示を試す場合は、Alexa ハローAPL、Alexaスキルの画面への対応を参考しましょう。
APL{ "document": { "type": "APL", "version": "1.1", "settings": {}, "theme": "dark", "import": [ { "name": "alexa-layouts", "version": "1.0.0" } ], "resources": [], "styles": {}, "onMount": [], "graphics": {}, "commands": {}, "layouts": {}, "mainTemplate": { "parameters": [ "payload" ], "items": [ { "type": "Container", "items": [ { "hintText": "${payload.sample.properties.hintText}", "type": "AlexaFooter", "top": "85vh", "position": "absolute" } ] } ] } }, "datasources": { "sample": { "properties": { "hintText": "ヒント" }, "transformers": [ { "inputPath": "hintText", "transformer": "textToHint" } ] } } }まとめ
今回は、AlexaFooterを使ってみました。
AlexaFooterは、ヒントを載せるためのものということで、あまり変わった用途では使えないかなという感触です。
また、ヒントは表示され続けますので、一時的にだして消すというような使い方でもなさそうで、追加する場合は、あらかじめこのスペースはフッター用として準備して他のレイアウトと被らないようにしておいたほうが良いのかなと思いました。
- 投稿日:2019-08-27T19:14:02+09:00
lint-staged で大量ファイルをlintしようとすると死ぬのを回避する (windows)
とあるプロジェクトで
lint-stagedを仕掛けて楽しようとしたら思わぬところでハマったので解決策を書いておく。やったこと
プロジェクトで使ってるlinterとformatterを手動でかけるのがめんどくさいので
git commit時に走るようにセットアップしていた。
使っていたツールは以下。
angular-cli@7.3.9: angular のプロジェクトなのでng lintをlinterとして使っている。husky@2.7.0: pre-commit hook を仕掛けるのに使っている。prettier@1.18.2: formatterpretty-quick@1.11.1:git addされたファイルにだけ prettier を実行するのに使っている。lint-staged@9.2.3:git addされたファイルにだけ linter を実行するのに使っている。ng-lint-staged@0.1.6:ng lintをlint-stagedと一緒に使うために必要。セットアップ
package.json{ // (省略) "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*": [ "pretty-quick --staged", "ng-lint-staged lint --fix --", "git add" ] } }ふつうはこれでだいたい動く。
ハマったこと
ある日突然チームメンバーの一人が「コミットしようとしたらよく分からないエラーが出る」とのこと。
よく分からないとはなんぞやと思ってエラーメッセージを見せてもらうと、文字化けしていて本当によく分からない。(最後まで文字化けは解読できなかった。)
その時の状況は下記のような感じ。
- 死んだコマンドは
ng-lint-staged lint --fix --らしい- そのメンバーが使用していた PC は Windows10 で、ターミナルには PowerShell を使用
- 僕が使用しているのは MacBook Pro で、ターミナルには fish を使用
git commit --no-verifyでとりあえずコミットしてもらい、僕のPCで再現させようとするも再現しない。- 手元に Windows 機もあったのでそっちで試してみると再現。
- コミットしようとしていたファイルは 150ファイル超
実行中のログをよくよく眺めてみると、途中で 「ステージングされているファイルが多すぎて、この環境ではコマンドが意図しない動作をすることがあるよ」 というようなメッセージがあることを発見。
調べてみると、 Windows の cmd.exe ではコマンドとして渡せる文字列は 8192 文字が限界 という記述を発見。
PowerShell でも似たような制限があるのではないかと推測した。解決策
lint-stagedではlint-staged.config.jsという名前で設定ファイルが書け、こちらだと実行するコマンドを自由に書き換えることができるようです。
package.jsonからlint-stagedに関する記述を削除し、lint-staged.config.jsに移行します。lint-staged.config.jsconst path = require("path"); const isTooManyFiles = (filenames) => filenames.length > 20; const toRelative = (absPaths) => absPaths.map((file) => path.relative(process.cwd(), file)); module.exports = { "{src,cypress}/**/*.ts": (filenames) => { const relativePaths = toRelative(filenames); console.log(`{src,cypress}/**/*.ts: targets are ${relativePaths.length} files.`); const lintCmd = isTooManyFiles(relativePaths) ? "ng lint --fix" : `ng lint --fix --files "${relativePaths.join(",")}"`; const gitCmd = isTooManyFiles(relativePaths) ? "git add src/ cypress/" : `git add ${relativePaths.join(" ")}`; return ["pretty-quick --staged", lintCmd, gitCmd]; }, "package.json": (filenames) => ["fixpack", `git add ${toRelative(filenames).join(" ")}`], };すごく見づらいスクリプトですが、やっていることはざっくり以下。
- ステージングされているファイルが20以上あったら、個別にlint/formatするのを諦めて全体をlint/formatする。
- ついでに
ng lint --filesオプションに合うように引数リストをパースする。これによってng-lint-stagedを使う必要がなくなる。- ついでのついでに
package.jsonに変更があったらfixpackして整形しておく。まとめ
コミットはこまめにしようね…。
(squash したらこうなることもあるのかな?)
- 投稿日:2019-08-27T19:00:32+09:00
スマートロックが壊れたのでobnizを使ってハックしてみた
こんにちは、わみです!
ギークハウス新宿では住民の入れ替わりの季節で住民減です!
こういうハック的な事に興味がある人いたら私のTwitterにメッセージしてくれると!なにをしたのか
壊れてしまったスマートロックからモータの制御や現在のポジションを取得するために制御を乗っ取り、obnizから指示を出すプログラムを作ってみました。
obnizでsesameをハックしてみた! pic.twitter.com/kdtwpJw26x
— わみ@NefryとかFlutter本とか (@wamisnet) August 27, 2019Sesameを導入した話:https://speakerdeck.com/wamisnet/sieahausunisumatorotukuwotuketemita
きっかけ
開発合宿にてSuicaで鍵を開けるシステムを作ったときにSesameのAPIを使ったのですが待ち時間が少々長く、実際に使うときにストレスになりそうだと思いました。
10秒ぐらいかかってましたね…
かかるタイミングだと気持ち1分ぐらい待ったような…玄関で待ちぼうけ(´・ω・`)
API以外は不満がなかったのでSesameをハックできないかと思い、Sesameを開けてみることにしました。
BLEモジュールやモータドライバーなどが取り付けられていることを確認したのち元に戻そうとしたとき…
「じゅっ」というどこかが壊れた音がしました
慌てて、電源を外しましたが時すでに遅し
もう動かなくなってしまいました
普通ならあきらめて新しいのをもう一つ買うところですが、せっかくだから思いっきりハックすることにしました!
技術構成
上の図のように連携しています。
- ハードウエア(Sesame)
- obniz (おすすめ記事)
- Node.js(別のサービスと連携するのでAPIを作成)
obnizを使うと何がいいのかというとわざわざハードウエアのコードを別に書かなくてもよくて、今回であればAPIとして使うためのNode.js一つだけでハードウエアの制御ができるところですね!
せっかくなのでちょっとづつ深堀りしていきましょう。
ハードウエア
obnizにモータドライバーついているので回路はすごくシンプルでモータとソレノイドを制御する部分+鍵のポジションを取得するためのアナログ入力をそれぞれ繋いでいます。
(はんだ付けが汚いのはご愛嬌)
obniz
モータとソレノイドの制御、アナログ入力を変換してくれます。
これがあるから、Node.jsで書くことができます。Node.js
とりあえずで作ったコードなのでダメな部分ありますが、ご容赦を!
https://github.com/wamisnet/key_controller/
鍵を開ける処理(APIでリクエストがあるとき)
- 現在位置を取得して、平均値をとる
- 現在位置から目的の角度に近い方にモータを回す
- ソレノイドを出す
- 目的の角度になるまで現在位置を取得し続ける
- 目標角度になったら、モータを止める
- ソレノイドを引く
といった処理を行ってます。
まとめ
こんな感じでハックしてみました。
動画で分かるようにボタンを押してすぐ動作するようになって目標は達成しました!!
obnizだったので回路もコードもシンプルに作ることができて便利だなと思いました。
ただ玄関で使用するときには、無線LANが不安定過ぎてobnizに向いていなかったので実際に使うことはできなかったです( ;∀;)
とっても悲しい
3日ぐらいずっとこれやってたので買った方が安かった気がする…
とはいえ自分で作れるのは楽しいですね!
今回バラしてしまいましたがSesame優秀なので、使うときはぜひ!
AkerunやQrio、Sesameと使ってきましたが、さらにいいデバイスがあれば教えてもらえるとうれしいです!
ここまで読んでくれた方へ
ここまで読んでくださりありがとうございます。
いいねやコメント、SNSでの共有等をしてくださると、今後の励みになります。よろしくお願いします。
良かったらTwitterもフォローしてね
ぎーじゅくの別記事
- Node-REDでシェアハウスのお風呂を爆速でハッキングする方法 : https://qiita.com/retoruto_carry/items/00ec51a94d819925fad1
- Reactとタブレットでバーコード使ったシェアハウス物々交換システム作った話【個人開発】: https://qiita.com/wamisnet/items/1c6f809be7c4847a900d
- 投稿日:2019-08-27T18:28:04+09:00
typescriptでaurora-serverlessからdata-apiでデータを取得する
AuroraServerlessを使うことで、https経由でデータアクセスが可能となる。
事前準備
- AuroraServerlessを構築する
- DataAPIをオンにする
- AWS Secrets Manager へ 認証情報を保存する
データの取得
- 環境変数に接続情報をセット export DB_SECRET_ARN="arn:aws:secretsmanager:ap-northeast-1:99999999:\secret:rds-db-credentials/cluster-XXXXXXXXXXXXXXX/xxxxxxxxxxx"; export DB_ARN="arn:aws:rds:ap-northeast-1:xxxxxxxxxxxxx:cluster:xxxxxxxxxxx"; export DB_NAME=xxxxxx
find_by_sql.ts// SQLから連想配列で取得する const find_by_sql = async (sql: string, parameters?: SqlParameter[]) => { const params: ExecuteStatementRequest = { resourceArn: process.env.DB_ARN, secretArn: process.env.DB_SECRET_ARN, sql: sql, database: process.env.DB_NAME, includeResultMetadata: true, parameters: parameters }; // データの取得 let res = await new Promise<ExecuteStatementResponse>((resolve, reject) => { RDS.executeStatement(params, (err, data) => { if (err) reject(err); else resolve(data); }); }); // 詰め替える const results: any[] = []; res.records.forEach(record => { const result_row: any = {}; res.columnMetadata.forEach((col, i) => { result_row[col.name] = Object.values(record[i]).filter(x => x)[0] || null; }); results.push(result_row); }); return results; }; // example const sql = 'select * from users where id = :user_id' const datas = await find_by_sql(sql, [{ name: "user_id", value: { stringValue: 'hoge' } }]);
- 投稿日:2019-08-27T13:17:45+09:00
TypeScriptでConnpassイベントの参加者を取得する
本稿ではTypeScriptでConnpassイベントの参加者を取得する方法を説明する。
get-connpass-applicantsモジュールをインストールする
yarn add @suin/get-connpass-applicantsこのモジュールは、ConnpassイベントのURLを渡すと、そのイベントの申込者情報を返してくれるもの。
実装
上記のモジュールを使って、任意のConnpassイベントの参加者を取得してみる。
main.tsimport { getConnpassApplicants, Applicants } from '@suin/get-connpass-applicants' (async () => { const url = 'https://yyts.connpass.com/event/144568/' const applicants = await getConnpassApplicants(url) console.log(JSON.stringify(applicants, null, ' ')) })()実行結果
{ "participants": [ { "url": "https://connpass.com/user/OkinaKahiro/", "name": "kahirokunn", "participationType": "現地参加" }, { "url": "https://connpass.com/user/suin/", "name": "suin", "participationType": "主催者・スタッフ枠" }, { "url": "https://connpass.com/user/picric/", "name": "kakiuchi", "participationType": "現地参加" }, { "url": "https://connpass.com/user/zima_gen/", "name": "zima", "participationType": "現地参加" } ], "waitlist": [], "cancelled": [] }
participantsByParticipationTypeプロパティを参照すれば、申込み枠ごとにグルーピングした参加者リストも取得できる。戻り値はES6のMapで返ってくる。console.log(applicants.participantsByParticipationType)実行結果
Map { '現地参加' => [ Applicant { url: 'https://connpass.com/user/OkinaKahiro/', name: 'kahirokunn', participationType: '現地参加' }, Applicant { url: 'https://connpass.com/user/picric/', name: 'kakiuchi', participationType: '現地参加' }, Applicant { url: 'https://connpass.com/user/zima_gen/', name: 'zima', participationType: '現地参加' } ], '主催者・スタッフ枠' => [ Applicant { url: 'https://connpass.com/user/suin/', name: 'suin', participationType: '主催者・スタッフ枠' } ] }
- 投稿日:2019-08-27T11:09:43+09:00
YAML で画面設計書を書いて Markdown で出力する
タイトルの内容をこうやってみましたというレポートです。
経緯
- 小さめ(画面10未満)・比較的単純なWebアプリ案件の設計書を記述する必要あり
- 設計書のフォーマット・ファイル形式に指定はなし、ファイル出力の必要もなし
- 好きにやっていいとの指示
希望
- Word や Excel で書きたくない
- テキストベースで書いて、リポジトリ管理したい
- ソースと配置をなるべく分けたくない
- ソースはGitLab リポジトリで管理
案
- GitLab の Wiki に Markdown で記述する
懸念点
- Markdown では、画面設計書に必要な以下の内容を記述しにくい
- 表形式
- 定まったフォーマット(記述の自由度が高い)
打開策
- 内容は、YAML で記述する
- 表形式など表示を見やすくするために、YAML を読み込んで Markdown に変換する
YAML とは
人間が扱いやすい、構造化データ・オブジェクトを記述するためのデータ形式
公式Swagger Spec の記述形式としても有名ですね。
Swagger Editorみたいな感じで、画面設計書も記述できるといいなーと思ったのが、今回の試みの発端です。YAML が設計書の記述に合っているところ
- 階層構造が記述できる
- データが型を持つ
- 改行を含んだデータを含めることができ、わかりやすく記述できる
- JSON Schemaが設定できる
JSON Schema とは?
JSONの記述フォーマットを定義したもの
公式IDEに設定することで、入力補助やバリデーションチェックに利用できる
VSCode では、Extension YAML を使うことで、YAML のスキーマとして用いることができる
やったこと
JSON Schema を作成
1. 作成したいYAMLを一部分作成する
画面設計書なので画面要素1つ分の記述とか2. 1. で作成したYAML を JSON に変換する
Webサービス yaml2json を利用
3. 2. で作成したJSONを元に、JSON Schema を作成
Webサービス JSON schema.neatを利用
入力した値を元にSchemaのスケルトンを作ってくれる
JSON Schema を VSCodeに設定
- Extension YAML を追加する
- YAMLのsetting にJSON Schema を設定する
setting.json{ "yaml.completion": true, "yaml.validate": true, "yaml.hover": true, "yaml.schemas": { "./screen.json": [ "*.yml", ], }, "yaml.format.enable": true, }手順は VSCodeで快適に設定ファイルを書く 参照
画面設計書(YAML)を書く
VSCode で YAML をゴリゴリ書いていきます。
- Ctrl + space で入力補助がでます!(捗る!)
- Scheme と合わない記述については、エラー表示されます
- 入力パターンなど、Schema に追加したほうがよい内容は随時追加する → エラーが出るのでつぶしていく、の繰り返しで進めていきます
![]()
YAMLをMarkdown に変換する
YAMLを読み込み、テンプレートを埋めて出力するスクリプト書きました
- JavaScriptで記述、Node.js上で実行
- npmライブラリ
- js-yaml YAMLを読み込んで JavaScript Objectとして取得する
- handlebars JavaScript Object を使ったテンプレートエンジン
- https://github.com/N0NamedGuy/yaml2html/blob/master/yaml2html を参考に
テンプレート
Markdown形式のテンプレートを作成します
記述しやすくするため、YAMLのキー名を日本語にしてたんですが、テンプレートでもそのまま参照できましたscreen.hbs# {{画面名}} {{説明}} ## 画面イメージ  ## 画面項目 {{#each 画面項目}} --- ### {{名称}} ({{id}}) | ラベル | 種類 | 入出力区分 | 表示/非表示 | 入力可/入力不可 | 型 | 桁数 | 表示フォーマット | 入力チェック | | ------- | ------ | --------- | ---------- | ------------ | ----- | --------------------------------------------------------------------------------- | ------------------------------ | ---------- | | {{ラベル}} | {{種類}} | {{入出力区分}} | {{表示/非表示}} | {{入力可/入力不可}} | {{型}} | {{#with 桁数}}{{#if min}} 最小:{{min}}{{/if}}{{#if max}}最大:{{max}}{{/if}}{{/with}} | {{表示フォーマット}} | {{入力チェック}} | {{#if 初期表示}} #### 初期表示 {{初期表示}} {{/if}} {{#if 説明}} #### 説明 {{説明}} {{/if}} {{#if 備考}} #### 備考 {{備考}} {{/if}} {{/each}}感想
よかった点
- 設計書書く時に、バリデーションチェックかかるのめっちゃいい
- Schemaファイルを修正すると、すべての設計書で都度検証かかることで、記述が揃う
- YAMLは複数行の文字列を入れやすい&見やすいので、設計書の主な記述である、表形式・自由記述のいずれの形式にも対応できる
- ここにMarkdown入れられるので、記述効率も上がる(アウトラインは使えないけど、箇条書き・表形式など)
screen.ymlイベント: - id: init 名称: 初期処理 項目id: 操作区分: その他 画面遷移: 処理ID: 入力: 出力: 説明: | - マスタデータ(Master)を用いて、紐づく入力項目の選択肢を生成する - 初期値を設定する - 画面入力情報が無い場合は、空白 or 初期表示の値を設定する - 画面入力情報が既にある場合は、該当する項目に保存されている値を表示するいまいちな点
- 一通り記述した後、ちょっとだけ修正したい時に、変換するのが面倒くさい・忘れがち
- 何かでファイルの修正を感知してコマンド実行する的なものを仕込めば解決しそうだけど、今回至りませんでした…
今後やってみたいこと
- 決まったキーワードと遷移先を定義しておいて、自動でリンク作成する的なこと
- 設計書の相互参照って便利だしWikiの特性だと思うので使えるようにしてみたい
- pdf に出力
参考
YAML書き方
https://qiita.com/tfrcm/items/5f8e4c5795ce41b214d1#%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%E9%85%8D%E5%88%97
https://magazine.rubyist.net/articles/0009/0009-YAML.htmlJSON Schema書き方
https://www.ikemo3.com/manual/json-schema/
https://qiita.com/arumi8go/items/a9530cbd39ff545a7bbbhandlebars書き方
- 投稿日:2019-08-27T00:15:13+09:00
Nest.jsでコントローラ・サービスを作ってみる
Nest.jsを利用してコントローラとサービスを作ってみます。
現時点(2019/8/26)でNest.jsの記事が少ないので少しでも貢献できればと思い、簡単な内容ですが書くことにしました前提
HelloWorldまで出力していることを前提とします。
こちらの記事などを参考にしていただければと思います。
Nest.js を使ってみるコントローラの作成
Nest.jsではRubyonRailsのようにCLIを利用してコントローラやサービスを作成可能です。
早速作成してみます。CLIコマンド$ nest g controller (コントローラ名)実行結果$ nest g controller cats CREATE /src/cats/cats.controller.spec.ts (479 bytes) CREATE /src/cats/cats.controller.ts (97 bytes) UPDATE /src/app.module.ts (322 bytes)このコマンドにより、src配下にcatsディレクトリが作成され、その中にcontroller.tsファイルとcontroller.spec.tsファイルが作成されます。
controller.spec.tsファイルはテスト用ファイルです。app.module.tsファイル内の更新は、今回作成したコントローラを読み込むように修正されています。
コントローラファイルを修正してみる
CLIで作成されたばかりの状態はこのようになっています。
cats.controller.ts(修正前)import { Controller } from '@nestjs/common'; @Controller('cats') export class CatsController {}
localhost:3000/catsでこのコントローラが実行されるように書き換えます。cats.controller.ts(修正後)import { Controller, Get } from '@nestjs/common'; @Controller('cats') export class CatsController { @Get() findAll(): string { return 'This action returns all cats'; } }実行してみます。
$ npm start $ curl localhost:3000/cats This action returns all catsreturnに設定した内容が返却されました!
こちらでコントローラはOKです。もちろん GETだけでなく、POST、PUT、PATCH、DELETEなどのメソッドやクエリストリング・リクエストパラメータの取得も可能ですが、今回は一旦省略します。
サービスの作成
まずNest.jsの概念図をお見せします。
先ほど作成したコントローラでは、多くのMVCフレームワーク同様に、URIの設計やユーザーからのリクエストを受け取るなどの責務を担います。
実際のビジネスロジックについてはサービスレイヤーで行うべきですので、Nest.jsでも同様にサービスを作る仕組みが用意されています。こちらもCLIで作成可能です。
CLIコマンド$ nest g service (サービス名)実行結果$ nest g service cats CREATE /src/cats/cats.service.spec.ts (446 bytes) CREATE /src/cats/cats.service.ts (88 bytes) UPDATE /src/app.module.ts (386 bytes)このコマンドにより、src配下のcatsディレクトリ内に、service.tsファイルとservice.spec.tsファイルが作成されます。
app.module.tsファイル内の更新は、コントローラと同様に今回作成したサービスを読み込むように修正されています。
また、providersとして、今回作成したサービスが登録されます。app.module.ts@Module({ imports: [], controllers: [AppController, CatsController], providers: [AppService, CatsService], }) export class AppModule {}app.module.tsファイルのprovidersに登録されたサービスは、DI(いわゆる依存性の注入)が可能になります。
サービスファイルを修正してみる
ではサービスファイルも修正してみます。
CLIで作成されたばかりの状態はこのようになっています。cats.service.ts(修正前)import { Injectable } from '@nestjs/common'; @Injectable() export class CatsService {}cats.controller.ts(修正後)import { Injectable } from '@nestjs/common'; import { Cat } from './interfaces/cat.interface'; @Injectable() export class CatsService { private readonly cats: Cat[] = []; create(cat: Cat) { this.cats.push(cat); } findAll(): Cat[] { return this.cats; } }色々修正する
CatsServiceの中でCatインターフェースを呼び出しているので、こちらも作成します。
src/cats/interface/cat.interface.tsexport interface Cat { name: string; age: number; breed: string; }Catインターフェースの具象クラスも作成します。
src/cats/dto/create-cat.dto.tsimport { Cat } from '../interfaces/cat.interface'; export class CreateCatDto implements Cat { readonly name: string; readonly age: number; readonly breed: string; }CatsコントローラにもCatを作成・取得するAPIを追加します。
また、先ほど作成したcatsServiceをコンストラクタでセットしています。(DI)cats.controller.tsimport { Controller, Get, Post, Body } from '@nestjs/common'; import { CreateCatDto } from './dto/create-cat.dto'; import { CatsService } from './cats.service'; import { Cat } from './interfaces/cat.interface'; @Controller('cats') export class CatsController { constructor(private readonly catsService: CatsService) {} @Post() async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); } @Get() async findAll(): Promise<Cat[]> { return this.catsService.findAll(); } }API実行
作成したAPIを実行してみます。
$ npm start $ curl -X POST localhost:3000/cats -H 'Content-Type:application/json' -d "{\"name\":\"タロー\", \"age\": 1, \"breed\":\"ペルシャ\"}" $ curl -X POST localhost:3000/cats -H 'Content-Type:application/json' -d "{\"name\":\"マル\", \"age\": 2, \"breed\":\"アメショー\"}" $ curl localhost:3000/cats [{"name":"タロー","age":1,"breed":"ペルシャ"},{"name":"マル","age":2,"breed":"アメショー"}]このようにAPIが簡単に作成出来ました。
Nest.jsすごくいいですね!これからも色々と使ってみて記事を作成してみようと思います。
参考
NestJS公式ドキュメント
今回の内容の多くはこちらを参考にしました。












