- 投稿日:2020-10-06T22:50:24+09:00
Apex UpでNode.js × expressをAWS Lambda, API Gatewayに速攻デプロイしてみる
はじめに
Node.js × expressのAPIのデプロイ先としてLambdaを使おうと思ったのですが
手取り早くデプロイして試したかったので、Apex Upを使ってみた。今回はその時の備忘録Upとは
APIや静的ウェブサイトをLambda × API Gatewayに
upコマンドでデプロイしてくれるツールです。使ってみる
Upのインストール
curl -sf https://up.apex.sh/install | shプロジェクト作成
mkdir node-up cd node-up npm init entry point: (index.js) app.js # 自分はapp.jsに変更expressのインストール
npm install express touch app.js touch up.json # Upの設定ファイルapp.js
const express = require('express') const app = express() const { PORT = 3000 } = process.env app.get('/', (req, res) => { res.send('Hello World!') }) app.listen(PORT);Upの設定は以下の内容に設定
{ "name": "node-up" }これで設定は完了です。
最後にgit commitします。
git commitしとかないとupしたときにエラーが出てしまいます。git init git add . git commit -m "First commit"最後にデプロイします。
upしばらくすると以下のような内容が出てくるのでURLをチェックして表示されればおkです。
stack: complete (19.175s) endpoint: https://.../staging/削除
up stack deleteさいごに
Apex Upを使えば気軽にデプロイできるのでとりあえずデプロイしたいときは重宝しそうです。
参考資料
- 投稿日:2020-10-06T14:14:31+09:00
mongoseでfindして、そのobjectに値を追加できない | node.js
lean()使うとできるようになる。
Item.findById(req.params.id).lean().exec(function(err, doc) { ... });doc.new = "Hi"https://stackoverflow.com/questions/18554350/unable-to-add-properties-to-js-object
- 投稿日:2020-10-06T11:55:42+09:00
【備忘録】WindowsでNode.jsをアップデートする方法
プログラミング勉強日記
2020年10月6日
Node.jsのバージョンをアップデートするときに少し詰まったので備忘録として記録する。
Windowsではnが使えないので、今回はnodistを用いてNode.jsをアップデートした。0. nodistをインストールする
コマンドプロンプトで
nodist -vを実行してnoditが使えるかどうかを確認する。使えない場合は、インストールする。以下のようになっていればインストールはできている。コマンドプロンプト>nodist -v 0.9.1こちらのページからインストーラーをダウンロードしてインストールする。
1. Node.jsをインストールする
次に
nodist distでインストールできるバージョンの一覧を表示する。以下のようにとても長くなる。コマンドプロンプト>nodist dist 0.1.14 0.1.15 0.1.16 0.1.17 0.1.18 0.1.19 0.1.20 0.1.21 0.1.22 0.1.23 0.1.24 0.1.25 0.1.26 0.1.27 0.1.28 0.1.29 0.1.30 0.1.31 0.1.32 0.1.33 0.1.90 0.1.91 0.1.92 (省略) 11.0.0 11.1.0 11.2.0 11.3.0 11.4.0 11.5.0 11.6.0 11.7.0 11.8.0 11.9.0 11.10.0 11.10.1 11.11.0 11.12.0 11.13.0 11.14.0 11.15.0 12.0.0 12.1.0 12.2.0 12.3.0 12.3.1 12.4.0 12.5.0 12.6.0 12.7.0 12.8.0 12.8.1 12.9.0 12.9.1 12.10.0 12.11.0 12.11.1 12.12.0 12.13.0 12.13.1 12.14.0 12.14.1 12.15.0 12.16.0 12.16.1 12.16.2 12.16.3 12.17.0 12.18.0 12.18.1 12.18.2 12.18.3 12.18.4 13.0.0 13.0.1 13.1.0 13.2.0 13.3.0 13.4.0 13.5.0 13.6.0 13.7.0 13.8.0 13.9.0 13.10.0 13.10.1 13.11.0 13.12.0 13.13.0 13.14.0 14.0.0 14.1.0 14.2.0 14.3.0 14.4.0 14.5.0 14.6.0 14.7.0 14.8.0 14.9.0 14.10.0 14.10.1 14.11.0 14.12.0 14.13.0この中でバージョンを選びインストールする。
コマンドプロンプト> nodist + 13.14.0 > nodist 13.14.0 > node -v (確認) 13.14.02. npmをアップデートする
Node.jsをインストールすると、npmも同時にインストールされるが、nodistでインストールされたnpmのバージョンは古いことがあるので、コマンドでnpmのバージョンを確認し、アップデートする必要がある。
コマンドプロンプト> npm -v > nodist npm 6.14.4
- 投稿日:2020-10-06T08:09:04+09:00
WebアプリへのLINEログイン実装で少しハマったところ
WebサイトへLambda+Node.js+APIGateWayを含めて、LINEログイン機能を実装しようとした。
参考にしたサイトが
「WebアプリにLINEログイン機能を組み込む」
[URL] http://xp-cloud.jp/blog/2019/11/27/6116/非常に分かり易くて参考になったが、一部どうしても動かない(LINE認証画面が出てこない)為、エラーメッセージを眺めてみると、「stateが無い」といったことを言われているので、あらためて、LINE公式を確認すると
"queryStringParameters": { "error": "invalid_request", "error_description": "'state' is not specified." },stateというパラメータは「必須」ということだった。
LINE公式サイト:
https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request
パラメタに「state」を足してパラメタ付きのリンクをたたくと、無事に表示されたLINEログイン画面。
その他の動作(Lamda~APIGateway)に関しては問題なく稼働。ありがとうございます作者様。
- 投稿日:2020-10-06T03:11:55+09:00
VagrantにHerokuを入れる際に起きたエラーと解決方法と参考記事
はじめに
ドットインストールで構築したローカル環境でアプリを開発し、公開するため、いざherokuを入れようとしたらエラーが起きまくりました。
【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】
この記事を参考にしていました。
しかし、herokuを入れる際に、この記事の開発環境が全く違うため、その先に進めずエラーと戦うことになりました。パスがない問題
エラー解決に必死だったため、エラーのコピーは取っていませんが、このようなエラーがでたと思います。
↓エラーの最後の文 Your path is missing /usr/local/bin, you need to add this to use this installer.
/usr/local/binのパスが無いと言われているため、パスを作る必要があるみたいです。パスの確認
$ echo $PATHパスを確認してみますが
/usr/local/bin:はあっても/usr/local/binがないと駄目みたいです。解決方法の前に、解決する中で知った知識
sudoとは、僕の解釈では権限の高いコマンド。
$と#で違いもあり、#のほうが権限が高い。($の方で実行できないことが#で実行できたから)解決方法:偉い権限を使ったり、
viエディタで書き換えたりする。パスの設定に必要な
.bash_profileの設定とsudoの設定は以下を参考にしました。
仮想環境構築後に設定しておきたいこと -メモ-
sudoの設定はこちらの方が親切です。
CentOS で sudo 時に実行ユーザーのPATHを引き継ぐ$ sudo visudoの実行後に、viエディタの操作が必要だったため以下を参考にしました。
viエディタの使い方パスが通ったと思ったら、シンタックスエラー問題
$ heroku --versionherokuのバージョン確認をすると、以下のエラーが...
/usr/local/lib/heroku/node_modules/@oclif/command/lib/index.js:3 const path = require("path"); ^^^^^ SyntaxError: Use of const in strict mode. at Module._compile (module.js:439:25) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.require (module.js:364:17) at require (module.js:380:17) at Object.<anonymous> (/usr/local/lib/heroku/bin/run:5:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32)Node.jsのバージョンが古すぎたみたいです。
$ node -v確認してみたところ
v0.10.48でした。解決方法:キャッシュを消して、新しいバージョンを入れる。
いろいろと試したため、ダイレクトな解決方法にならない場合はすみません。
npmがインストールされていなかったので、インストールしました。ついでにnodeもインストール。
Herokuを入れるためにnpmが必要かどうかはわかりませんが、とりあえずインストールしました。$ sudo yum install nodejs npm偉い権限の方に行く。
$ sudo -s左のやつが
$から#に変わる。インストールするために必要なやつ(正直、よくわかってないですが
setup_11.xの数字の部分でインストールするバージョンを指定。)# curl --silent --location https://rpm.nodesource.com/setup_11.x | bashここから、インストールとアンインストールを繰り返したため、手順が間違っていたらすみません。
以下を参考にしました。先の読んでおいて欲しいです。
yumでのnodejsのバージョンアップにはまった話と解決方法古い方のrpmを削除。
# rm /etc/yum.repos.d/nodesource-el.repoアンインストールする。
# yum -y remove nodejsキャッシュを削除。
# yum clean allインストールする。
# yum -y install nodejsバージョンを確認。
# node -v v11.15.0成功です!
そして、偉い権限のところから出る。# su vagrantherokuのバージョンも確認
$ heroku -v heroku/7.44.0 linux-x64 node-v11.15.0他の参考記事です。
https://qiita.com/daskepon/items/16a77868d38f8e585840
https://inaba.hatenablog.com/entry/2018/11/13/023933ほぼ同じエラーが出ていた記事
https://teratail.com/questions/256490感謝
参考にさせていただいたサイト管理人の皆様、誠にありがとうございました。
- 投稿日:2020-10-06T00:12:54+09:00
Amazon Echo で Google Drive 上の mp3 を 再生する (その2)
はじめに
前回の記事 のコード部分を説明します。
AudioPlayer のリファレンスはこちら。AudioPlayer の使い方(考え方)
プレイリストの曲をすべて再生することだけを考えるなら、最初に全ての曲をキューに登録してしまうという使い方もあります。しかし後に実装する次の曲、前の曲、シャッフル再生などは任意のタイミングで指示され、登録していたキューが無駄になることもあるため、以下の考え方で使用します。
- キューには 1 曲しか登録しない
- 次の曲、前の曲、曲の終了、などのリクエストにより、次に再生する曲をキューに入れ替え登録する (再生中の曲をそのままに登録する方法と、再生中の曲を含めて入れ替える方法があり使い分ける)
- 機能に必要な情報はトークンに埋め込み、次回リクエスト時にトークンから必要な情報を取得する
トークンについて
トークンについてはリファレンスの
audioItem.stream.tokenに記述がありますが、再生中の曲(ストリーム)を識別するための 1024 文字以内の任意の文字列です。このトークンに情報を埋め込むことで、DB 等に再生中の曲の情報を保存したりせずに必要な機能を実現します。
今回、トークンはコロン ( : ) で区切った以下の形式で組み立てることにします。
プレイリストファイルID:乱数seed:再生曲番号:ループ再生フラグ:リピートフラグ:曲情報テキスト
項目 説明 プレイリストファイルID 再生中のプレイリスト(json) の Google Drive 上のファイルID です。これにより再生開始後は root.jsonを見る必要がなくなります。乱数seed シャッフル再生用の項目です。0 が順次再生、0 以外がシャッフル再生です。未実装部分 再生曲番号 現在何曲目を再生しているかの番号です。 ループ再生フラグ loopなら全体ループ再生、空文字列なら一度限り再生を示します。未実装部分リピートフラグ repeatなら次回も同じ曲を再生(1回のみ)、空文字列なら次の曲を再生します。未実装部分曲情報テキスト 曲名を訪ねた際に読み上げるテキストです。コロンを含めないよう注意が必要です。未実装部分 コード概説
getRequestTypeOrIntentName() (index.js 11行目~)
今回のスキルでは、RequestType か IntentName で処理を分岐しますが、その分岐をしやすくするため適切な方の値を返却するだけの関数です。
const getRequestTypeOrIntentName = handlerInput => { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' ? Alexa.getIntentName(handlerInput.requestEnvelope) : Alexa.getRequestType(handlerInput.requestEnvelope); };LaunchRequestHandler() (index.js 17行目~)
「Alexa、プレイミュージックを開いて」などとスキルの起動のみが行われた場合の処理です。
プレイリスト名の発話を促す返答を行い発話待ちにします。const LaunchRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; }, handle(handlerInput) { const speakOutput = 'プレイリスト名を教えてください。'; return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } };PlayMusicHandler() (index.js 30行目~)
個別に見ていきます。
canHandle(), async handle()
canHandel() で
PlayMusicIntentかAudioPlayer.PlaybackNearlyFinishedの場合にtrueを返却することで、それらのリクエストが発生した場合に handle() が呼び出されます。
未実装のリクエストは 94行目のCancelAndStopIntentHandler()に記述してあるので、実装が完了したものは随時こちらの配列に移していく形になります。
handle() の基本的な処理の流れは以下になります。
- 再生用パラメータを初期化 (38行目~44行目)
- リクエストに応じて再生用パラメータを調整 (45行目~)
- 再生する曲の url とトークンを作成 (85行目~87行目)
addAudioPlayerPlayDirectiveで再生を指示 (88行目)PlayMusicIntent (index.js 46行目~)
PlayMusicIntentは 2.3.4. インテント で設定したサンプル発話に合致する発話がなされた場合にリクエストされます。
再生パラメータの初期値は初回再生時と同じであるため変更しませんが、プレイリストのファイル ID が未取得のため、{playlist}スロットに格納されたプレイリストのidをキーに、root.jsonからプレイリストファイルのファイル ID だけ取得します。case('PlayMusicIntent'): { // intent.slots.{スロット}.resolutions 配下にユーザーが選択したスロットが格納される // ユーザーが発話したプレイリスト名に対応する Google Drive 上の json ファイルを取得するが、 // スロット値の ID を利用することで、発話の揺らぎに対応しつつ対象ファイルを一意にしている const resolvedSlot = handlerInput.requestEnvelope.request.intent.slots.playlist.resolutions.resolutionsPerAuthority[0].values; if (resolvedSlot === undefined) { const speakOutput = 'プレイリストを認識できませんでした。もう一度お願いします。'; return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } const rootjson = await getJson(makeDriveUrl(rootFileId)); playlistId = rootjson.playlists[resolvedSlot[0].value.id]; break; }AudioPlayer.PlaybackNearlyFinished (index.js 62行目~)
AudioPlayer.PlaybackNearlyFinishedは曲の終わりが近づいてキューに次の曲を追加できるようになった時に自動的にリクエストされてきます。
behavior の初期値のREPLACE_ALLは再生中の曲が終了してしまうため、再生中の曲に影響を与えずにキューを置き換えるREPLACE_ENQUEUEDに変更します。
また、再生中の曲のトークンから再生パラメータを切り出し、次の曲にするため再生曲番号を+1します。この段階ではプレイリストに何曲あるか分からないため+1した結果が最後の曲を超えているかどうかは 75 行目で考慮しています。case('AudioPlayer.PlaybackNearlyFinished'): { // 曲の終了間際の場合は再生中の曲をそのままにするため REPLACE_ENQUEUED でキューを置き換える behavior = 'REPLACE_ENQUEUED'; const audioPlayer = handlerInput.requestEnvelope.context.AudioPlayer; [playlistId, seed, track, loop, repeat, ] = audioPlayer.token.split(':'); track = (+track) + 1; break; }プレイリスト取得 (index.js 75行目~)
root.jsonまたはトークンから取得したプレイリストのファイル ID からプレイリストデータを読み込みます。
ここで全曲数がわかるため、次の再生曲番号が最後の曲を超えていたらキューをクリアして終了します。「再生を終了します」などのアナウンスをしたいところですが、AudioPlayer.Playback~では.speakによる発言ができない仕様になっています。// 全て再生したら終了する const playlist = await getJson(makeDriveUrl(playlistId)); if (track >= playlist.length) { return handlerInput.responseBuilder .addAudioPlayerClearQueueDirective('CLEAR_ALL') .withShouldEndSession(true) .getResponse(); }再生指示 (index.js 84行目~)
情報が揃ったため、再生指示の応答を返却します。
idxはシャッフル再生時にtrackとずれるため用意しています。// addAudioPlayerPlayDirective を利用して AudioPlayer に音楽再生の指示を応答する const idx = track; const url = makeDriveUrl(playlist[idx].id); const token = `${playlistId}:${seed}:${track}:${loop}:${repeat}:${playlist[idx].info}`; return handlerInput.responseBuilder .addAudioPlayerPlayDirective(behavior, url, token, offset, null) .getResponse();getJson (index.js 180行目~)
指定した (Google Drive の) URL の json データを読み込む関数です。
uc?export=download&id=を使うと直接ファイルにアクセスできているように見えますが、一度リダイレクトされています。
httpsモジュールは、リダイレクトを追跡するようにはなっておらず、追跡できるrequestモジュールは標準では使えませんので、httpsモジュールを使って簡易的にリダイレクトを追跡する処理を組みます。const getJson = (url) => new Promise((resolve, reject) => { Https.get(url, (res) => { res.setEncoding('utf8'); let json = ''; if(res.statusCode === 301 || res.statusCode === 302) { resolve(getJson(res.headers.location)); } else { let bufs = []; res.on('data', (chunk) => json += chunk); res.on("end", () => { try { resolve(JSON.parse(json)); } catch (err) { console.log(err); reject(err); } }); res.on('error', (e) => { console.log(e.message); reject(e); }); } }); });おわりに
無駄に長くなっていまいましたが以上になります。つまづく箇所はリダイレクトの追跡くらいでしょうか。
その3 では未実装機能を実装します。参考
- Stack Overflow : How do you follow an HTTP Redirect in Node.js?



