20220114のNode.jsに関する記事は6件です。

Expressのテンプレートエンジンにejsを使う時、ejs内でexpressのlocalsを参照できる

はじめに Expressでテンプレートエンジンejsを使った実装をする時に、ejs内ではExpressのlocalsを参照できるという事を知ったので、具体的にどうなるのか?を少しまとめてみた。 ejs内ではexpressのapp.localsやres.localsのlocalsを参照できる res.render(view [, locals] [, callback])には、 locals, an object whose properties define local variables for the view(ビューのローカル変数を定義するプロパティを持つオブジェクト). と書かれているので、あくまでres.render()の第二引数に渡す値のみがテンプレートエンジン内(ejs)で使えるのかと思っていたが、実際にはejs内ではlocalsというオブジェクトに、res.render()の第二引数のオブジェクトと、expressのlocals(app.localsやres.localsのlocals)に定義済みのオブジェクトが全て組み込まれており、それらがすべて使える。 実際に、以下のようなソースを書いてみた時にの画面の描画内容からもこの事は確認できた。 <body> ... <% for (let local of Object.keys(locals)) { %> <li><%= local %></li> <% } %> ... </body> ↑ は、以下の実装において、app.locals.poolやapp.locals.fsSql、res.locals.momentやres.locals.paddingという設定をしていることにより、locals内にpool・fsSql・moment・paddingなどが存在している。また、その他のid、nameなどは、SQLの戻り値として返ってきたもので、res.render()の第二引数に渡しているので存在している。 ※paddingは関数であるが、これはexpressのres.localsには変数(値)だけでなく、オブジェクトや関数を渡す事もできるので、ejs内でlocals内に定義した関数を呼び出す事も可能。関数をejs内で呼び出す例としては、ここを参照。また、関数をres.localsに定義している部分は、ここを参照(localsを明示的に書いているが、省略してpaddingとする事も可能)。 client.js#L7 // https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/lib/database/client.js#L7 app.locals.pool = pool; app.locals.fsSql = new SqlQueryLoader({ path: 'src/lib/database/sqls' }); app.js#L22 // https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/app.js#L22 app.use((req, res, next) => { res.locals.moment = moment; res.locals.padding = padding; next(); }); shops.js#L14 // https://github.com/yuta-katayama-23/post-restaurant-reviews/blob/657bfebd338886c532a32f80b65146543de75623/src/routes/shops.js#L14 try { const [rows] = await pool.query( fsSql.readSync('tran_shops', 'SELECT_SHOP_DETAIL_BY_ID'), [id] ); res.render('./shops/index.ejs', rows.shift()); } catch (err) { next(err); } ※ソースコードの全体は以下。 ※expressのapp.localsについては、app.localsを参照。 参考文献 Node.js - How can I use my local variable with EJS view Using template engines with Express
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fnm (Fast Node Manager) のインストール方法と使い方

これまで Windows で Node.js のバージョン管理は Nodist を利用していましたが、2019年3月30日のリリース以降更新されていません… そんな理由から別のバージョン管理ツールに乗り換えをすすめる記事をちらほら見かけるようになりました。 乗り換えなければと思いつつ、 Node.js が利用できなくなると仕事にならない 種類が多くてどれを選んだらいいのかわからない インストールが大変そう という理由からずっとスルーしていました… しかし、以下記事と出会い、 fnm (Fast Node Manager) に乗り換えることにしました! fnm の詳細は以下をご覧ください。 というわけで、 fnm のインストール方法を紹介します。 ちなみに Nodist は以下の手順でアンインストール 「プログラムと機能」を開き、Nodist をアンインストール Nodistフォルダ削除 C:\Program Files (x86)\Nodist npm-cacheフォルダ削除 C:\Users<ユーザー名>\AppData\Roaming\npm-cache mac の場合 以下コマンドを実行するだけでインストール完了です curl -fsSL https://fnm.vercel.app/install | bash Windows の場合 以下からダウンロードし、PATH が通っているところに置くだけで利用できるようですが、設置場所がわからないので Chocolatey を利用してインストールしていきます。 1. Chocolatey のインストール 1-1. コマンドをコピー 公式サイトにアクセスします。 Step 2 の「Choose How to Install Chocolatey」はデフォルトで Individual(個人)が選択されているのでそのまま。 「Now run the following command:」下のコマンドをコピーしておきます。 1-2 管理者権限で PowerShell を起動 PowerShell を検索 PowerShell を右クリック → 管理者として実行 1-3. PowerShell でコマンドを実行 1-1. でコピーしたコマンドを貼り付けて実行すると最新版のインストールが始まります。 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) ログ中に Chocolatey (choco.exe) is now ready. と出てればインストール完了です。 1-4. インストールの確認 正常にインストールできたか確認のため、以下コマンドで Chocolatey のバージョンを確認します。 choco -v > 0.11.3 2. fnm をインストール 管理者権限で PowerShell を起動し、以下コマンドを実行。 choco install fnm -y 3. シェルセットアップ 利用するシェルに合わせて fnm の初期化処理を設定する必要があります。 コマンドプロンプトの設定はレジストリをいじる必要があったり面倒なので、PowerShell だけで利用することにしました。 3-1. Windows PowerShell & PowerShell プロファイルファイルを Microsoft.PowerShell_profile.ps1 という名前で作成し、以下コマンドを記述します。 Microsoft.PowerShell_profile.ps1 fnm env --use-on-cd | Out-String | Invoke-Expression 作成したプロファイルファイルを以下に格納します。 Microsoft.PowerShell_profile.ps1 の格納場所は PowerShell で `$profile` と入力すると確認できます。 すでにファイルがある場合はコマンドを追記してください。 # Windows PowerShell C:\Users<ユーザー名>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 # PowerShell C:\Users<ユーザー名>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 4. インストールの確認 正常にインストールできたか確認します。 PowerShell で以下コマンドを実行し、バージョン番号が表示されればインストールは終了です fnm -V > fnm 1.29.2 fnm の使い方 fnm のコマンドの一覧は以下ページで確認できます。 インストールできるバージョン一覧 fnm list-remote インストール fnm install {version} アンインストール fnm uninstall {version} 利用するバージョンの指定 fnm use {version} # デフォルトのバージョンを指定する場合 fnm default {version} 利用するバージョンの確認 fnm current # 一覧で確認 fnm list プロジェクトで利用する Node.js のバージョンを変更する プロジェクトのルートディレクトリに利用したい Node.js のバージョンを記述した .node-version ファイルを設置しておくと自動的にバージョンを変更してくれます。 \スッゴイ便利/ .node-version v14.18.3 指定されたバージョンがない場合は、以下のように fnm がインストールするか聞いてきます。 Can't find an installed Node version matching v14.18.3. Do you want to install it? answer [y/n]: 以下コマンドを実行すると現在利用中のバージョンを記述した .node-version ファイルが生成されます。 node -v > .node-version
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Express.jsにPassport.jsで、任意のフォルダ配下のみをBasic認証する その2

概要 expressを使って特定フォルダのみパスワードを掛けたい。 こんどこそ、express-basic-authを使って。 const express = require("express"); const basicAuth = require("express-basic-auth"); const PORT = 3000; const app = express(); // app.use("/admin", basicAuth({ users: { 'user': 'pass' }, challenge: true, }), express.static("public/admin")); // app.use("/", express.static("public/") ); app.listen(PORT, () => { console.log("app listening on port " + PORT + " " + new Date()); }); 結論 やったー。動いた!ばんざーい。 よっしあぁ。 参考サイト git https://github.com/kawamurashin/express-auth-test Express.jsにPassport.jsで、任意のフォルダ配下のみをBasic認証する https://qiita.com/hoshimado/items/272fba1aeb728e14f278 express-basic-auth   https://github.com/LionC/express-basic-auth
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモ:node.jsのjestでユニットテスト

pythonのユニットテストpytestは軽く見たので、node.jsも見ておく。 現時点だとjestというのが一番良さそう。 [公式日本語版}(https://jestjs.io/ja/docs/getting-started)ぽいのや ここ、ここ を確認しながら。 インストール 単体だとnpm install jestだが npm install typescript jest @types/jest ts-jestで入れた。 実際の開発現場だと--save-devしてるのかも 27.4.5で入った。 jest -initコマンドを流すのだが C:\nodejs\jest>.\node_modules\.bin\jest --init Could not find a "package.json" file in C:\nodejs\jest とpackage.jsonがないとエラーになるようなので package.json { "scripts": { "test": "jest" } } を作成してから実行、y/nの選択肢が出てくるがエンター連打で良さそう。 実行テスト 適当なtarget.jsを作成してテストしてみる。 exportで出力する形の.js(もしくは.ts)をテストするのが基本のようなので公式に倣う。 中身は公式のスクリプトとほぼ同じもの。 target.js function sum(a, b) { return a + b; } module.exports = sum; テストは__tests__フォルダを作成して、target.test.jsを作成 特に設定をしない場合、jestは自動的にtests以下からxxxx.test.jsを見つける。 target.test.js const sum = require('../target'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); これでnpm testを実行する事でTests: 1 passed, 1 totalが出たのでOK 実際の使い方 比較式 expect(実行).toBe(答え) で基本的な関数のテストは行う事が可能。 この時===で比較するので注意。値比較で良いなら.toEqualも使える。 ○○以外ではない事を確認する事は少なそうだが、expect(x).not.toBe(y)を使う。 その他toBeNull,toBeTruthy,toBeFalsyなどが使える。 文字列はtoMatchで正規表現比較が可能。配列にはtoContain。 javascriptの正規表現はここ等で。 小数の比較の場合は丸め誤差(0.1+0.2と0.3の比較など)が影響するので toBeCloseToを使うと無視できる。 例外が出るかどうかについては expect(() => compileAndroidCode()).toThrow(); のようにラムダ式+toThrowで判定 プロパティを見るにはtoHaveProperty この辺りが主な判定方法で、全てを確認する場合はドキュメントを見る。 非同期 非同期系のコードをテストする場合の情報はここを参照。 Async/Awaitを確認。 jsonはhttp://jsonplaceholder.typicode.com/postsにアクセスして取得する。 node.jsのrequestが非推奨になっているので代わりにnpm install axios。 プロキシはオプションで設定する。 target.js const { assertJSXAttribute } = require("@babel/types"); const axios = require("axios"); const proxyConfig = { proxy: { host: 'hostname', port: '8080' } } function sum(a, b) { return a + b; } async function getjson(n){ return await axios.get("http://jsonplaceholder.typicode.com/posts/"+n ,proxyConfig ); } module.exports = getjson; テスト側でも普通にasync,awaitを使う。 target.test.js const getjson = require('../target'); test('json', async () => { const res = await getjson(3) expect(res.data.id).toBe(3); }); 事前処理 beforeとafterを利用する beforeEach(() => { initializeDatabase(); }); afterEach(() => { clearDatabase(); }); モック 公式の他 実装についてはここやここ考え方含めてはこことかが参考になるかも? 関数の場合はjest.fnを利用する。 const mockCallback = jest.fn(x => 42 + x); const mockFunc = jest.fn().mockImplementation(() => "mock func"); のようにする。 ライブラリの場合は jest.mock("random"); // jest.mockでモックを使う宣言をして test('should fetch users', () => { const users = [{name: 'Bob'}]; const resp = {data: users}; axios.get.mockResolvedValue(resp); // getをCallした時にmockが返す値をセット // もしくはmockImplementation // or you could use the following depending on your use case: // axios.get.mockImplementation(() => Promise.resolve(resp)) // Usersクラスのstaticなallをチェック return Users.all().then(data => expect(data).toEqual(users)); }); 基本はなんとなくわかった気になった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Symbolブロックチェーンで不正な署名要求を検知し、注意喚起のメッセージを送る方法

現在Symbolブロックチェーン上で、全額振り込みのトランザクションに署名させる詐欺が確認されています。今回はそういった詐欺行為を検知し、注意喚起のメッセージをトランザクションに載せて自動で送信する方法を紹介します。 いつもはBrowser上のJavascriptで紹介していますが、今回は常駐させる必要があるのでNodeJS上で動かします。もちろんブラウザ上で起動させて、イベント期間中だけ入金したアカウントにチケットを配布させるローコードでデプロイレスなスマートコントラクトとして利用するなども可能です。ソースコードについては以下の記事を参考にさせていただきました。 const sym = require("symbol-sdk"); const nodeURL = 'https://node.xembook.net'; //詐欺アカウント const scamAddress = sym.Address.createFromRawAddress('NA3H3EXNWIARYBYGIMOQFKWPD2KSV2DFLGCO***'); //リポジトリ関連の設定 const repositoryFactory = new sym.RepositoryFactoryHttp(nodeURL); const listener = repositoryFactory.createListener(); const accountHttp = repositoryFactory.createAccountRepository(); const transactionHttp = repositoryFactory.createTransactionRepository(); const receiptHttp = repositoryFactory.createReceiptRepository(); const transactionService = new sym.TransactionService(transactionHttp, receiptHttp); // メイン処理 (async () => { //ネットワーク設定値 const networkType = await repositoryFactory.getNetworkType().toPromise(); const networkCurrency = (await repositoryFactory.getCurrencies().toPromise()).currency; const epochAdjustment = await repositoryFactory.getEpochAdjustment().toPromise(); const generationHash = await repositoryFactory.getGenerationHash().toPromise(); //注意喚起アカウント const alertAccount = sym.Account.createFromPrivateKey("***********",networkType); //リスナー起動、アグリゲートボンデッドトランザクションの発出を検知 await listener.open(); listener.newBlock().subscribe(); listener.aggregateBondedAdded(scamAddress).subscribe( async (partialTx) => { //詐欺トランザクションの詳細を取得 const txs = await transactionHttp.search({ address:partialTx.innerTransactions[1].signer.address, group:sym.TransactionGroup.Confirmed, embedded:true, }).toPromise(); //条件を満たした場合に注意喚起 if(true){ //注意喚起のトランザクション生成 const tx = sym.TransferTransaction.create( sym.Deadline.create(epochAdjustment), partialTx.innerTransactions[1].signer.address, [], sym.PlainMessage.create('【注意喚起】'), networkType ); //署名 const signedTx = alertAccount.sign(tx, generationHash); //ネットワークへアナウンス try { await transactionService.announce(signedHashLockTx, listener).toPromise(); } catch(err) { console.log(err); } finally { } } } ); })(); ブロックチェーン上の状態変化を検知し、新たなトランザクションを発生せる定番のパターンですので、ぜひマスターしていろいろな場面で活用してみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SORACOM LTE-M Button plusをトリガーに、LINE Notifyで位置情報を通知する

はじめに SORACOM LTE-M Button powered by AWSを以前使っていたのですが、紛失。 しかし最近このLTE-Mボタンを使う機会ができたので、これを機にLTE-M Button Plusを買いました。 そしてこのLTE-M ボタン Plusを使い、AWS lambda、そしてIFTTTを介してLINE Notifyの通知を使う事を実現してみました。 調べてわかったのですが、このボタンはPowered by AWSのモデルと違いボタンを押した位置座標を大まかではあるものの取得できる機能があります。そこで、今回はtwitterの動画にあるように、LINE Notifyに文章を送るだけでなく、今の位置情報をGoogle maps APIの中のStatick map APIを使って一緒に今の位置情報を画像で送ってみました。 この記事ではこの実現方法をまとめます。 開発環境 この記事の前提となる開発環境はmacOS Monterey AWS Lambdaのコードは node.js 12.x になります。 それでは開発を始めていきましょう SORACOM LTE-M Buttonを登録 このあたりはSORACOMさん公式のドキュメントがしっかりしていてとてもわかりやすいです。 まずは購入したらLTE-M Buttonを以下のリンクの手順に沿って登録します。 登録ができたら、SORACOM側の設定は一旦ストップです。 AWS Lambdaの関数を作成、LTE-Mボタンと紐付けする LTE-Mボタンの登録が終わったら、AWS Lambdaの関数を作成します。 ここで作成した関数は後ほどSORACOMのコンソールでSORACOM Funkの設定を行い、紐付けをします。 この辺りも私が説明を書くより、SORACOMさんのドキュメントがわかりやすかったのでリンクを貼っておきます 設定で注意するポイント 先述の手順通りに設定をすれば困らないのですが、LTE-M Buton plusはSORACOM Harvestにデータを送る事ができます。この機能をON,OFFするときに、”デバイスの設定変更”の項目を変更することになるのですが、保存をすると、SORACOM Funkの設定がメールを送信するSORACOM Funkが標準で用意しているARNに上書きされます。 だからと言ってチェックを外すとSORACOM Funk自体がOFFになってしまいます。 面倒ではありますが、デバイスの設定変更をした際は、あらためてSORACOMのコンソール上でSORACOM Funkの設定を行なってください この設定が終わればIFTTTの設定を行いましょう IFTTTの設定をする IFTTTではwebhook、LINE Notifyの組み合わせでAppletを一つ作成します。 それぞれの設定は以下のようにしました。 webhookイベントは任意でつけてください。 LINE Notifyも基本的にはお任せですが、今回はLTE-M ButtonのGPS座標を一緒に送ってみます。 そのため、PhotoURLにgoogle maps apiのURLを貼り付けます。 URLはコピペして設定してみてください。 こちら使ってもらえれば簡単に以下のような画像を取得する事ができます https://maps.googleapis.com/maps/api/staticmap?size=640x320&scale=2&center={{Value2}},{{Value3}}&zoom=18&key=***write your key****&language=jp&markers=size:normal%7Ccolor:red|{{Value2}},{{Value3}} ここででているValue2やValue3はLTE-Mで取得できるGPSの緯度、経度の情報になります。lamabdaからwebhookを介してjson形式で送られてきます。IFTTTではこれを変数として扱ってくれるので、変数として設定しました。 他の変数については以下のサイトを参考にみてください。他にも設定があり、実はいろいろな加工ができる事がわかります。 クエリのkeyの部分はGoogle Cloud Platformで設定をした際に入手できます。 こちらについては次に説明します。 Google Maps APIの設定をする LINE Notifyでmap画像が表示できるようにGoogle Maps APIの設定をします。 まずはご自身のアカウントでgoogle cloud platformを開いてください。 開いたら、プロジェクトを設定し、左側のスクロールビューからGoogle Maps Platformを選択します 選択したら、左のスクロールビューにある[認証情報]を選択し、右側のビューにある[認証情報を作成]を選択します。 クリックするとどの認証情報を作成するか選択肢がでてきますが、ここでは[APIキー]を選択します APIキーが作成できたら、このキーをコピーしましょう。 コピーしたキーはIFTTTのURLのクエリに貼り付けしておけばOKです。 ちなみに、IFTTTのJSON形式が固定されていて、3つのvalueしか送る事ができません。とはいえ工夫次第でキー自体を送ることも可能かと思います。今回はそのまま貼り付けて使いました。 これでIFTTTの設定やGoogle Maps APIの設定は完了です AWS Lambdaのコードを書く そのままコピペしてもらえれば使えるように、全コードを貼り付けます。 ただし、今回 requestモジュールを使っています。(外部モジュール) この外部モジュールを使うために、ローカルでデプロイパッケージを作成して、インポートを行なってください。 一応今回使うモジュールは npm install request でインストール可能です。 それではコードの中身をみていきます。 説明はコメントとしてコード内に記載しておきます index.js const https = require('https'); const url = require('url'); const request = require('request'); exports.handler = function(event, context, callback) { console.log('processing event: %j', event) //主にボタンのクリック情報などが取得できる //SORACOMのコンソールからデバイスの設定で位置情報取得を入れておくと、context内でGPS座標情報が取得できる! var eventName = event.clickTypeName //SINGLE,DOUBLE,LONGの3つが取れるようになっている。 var comment = "" if(eventName == null){ console.log("receive wrong data"); return } var values = [] var comment = "" //eventNameの中身を確認して、value1に入れるコメントを選ぶ switch (eventName) { case "SINGLE": comment = "ドライバーが何か電話をしたいそうです。" break case "DOUBLE": comment = "車両にトラブルが起きたことをドライバーが知らせています。" break case "LONG": comment = "ドライバー交代をしたいようです" break default : comment = "ドライバーが何か電話をしたいそうです。" break } // リクエスト設定 //今回はlambdaの環境変数を使っている。 //TRIGGERはIFTTTで自身が決めたEventNameを記載 //KEYはIFTTTのwebhookのドキュメントで確認ができる個人に与えられたキーを入力。 const options = { url: "https://maker.ifttt.com/trigger/"+process.env['TRIGGER']+"/with/key/"+process.env['KEY'], headers: { 'Content-type': 'application/json' }, body: { "value1": comment, "value2": context.clientContext.location.lat, "value3": context.clientContext.location.lon, }, json: true }; request.post(options,function(error, response, body){//postする。 if(!error && response.statusCode == 200){ //responseのステータスコードを確認して成功、失敗を判断する。 console.log('webhook succeeded') }else{ console.log('webhook failed failed with' + response.statusCode) } }); } これでlambdaのコードは完了。 デプロイしてLTE-Mボタンを押してみてください。LINEにこのような通知が届くようになります。 さいごに 数年前に使って遊んでいたLTE-M Button。今回はPlusを購入し、ボタンをトリガーにLINE Notifyに通知するというのをあらためてやってみました。 powered by AWSの方がもちろん簡単に構築はできるのですが、このPlusの方でも割と簡単にAWS Lambdaにメッセージを送る事が簡単にできて驚きました。SORACOMさんのサービスが充実しているということです!!ありがたい! また今回開発してわかったのですが、以前はnodeのurlモジュールでもIFTTTにwebhookをpostする事ができたのですが、現在はこの方法を使うと403が返ってきて動きません。(ラインタイムの影響?) そのため、requestモジュールを使ったプログラムを改めて作り動かしてみたところ、すんなり動きました。 もしうまく動かず困っている方はこちらの記事を参考にしていただければ幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む