- 投稿日:2019-08-28T21:54:04+09:00
Nuxt.js+TypescriptでのserverMiddlewareの利用について(実践編)
先日2019/08/26(月)に、NuxtMeetup#9で、
Nuxt.js+TypescriptでのserverMiddleware、のお話をさせていただきました。その時のスライドはこちらですー
Nuxt.jsのベストプラクティスを考えてみるもう少し、実践的な補足を記載しようかと思います。
私がよく使う自分でまとめたテンプレ
からちょっとソース抜粋してご説明します。テンプレはちょっと更新してないので、version 2.6.3ですが、この頃から serverMiddlewareの機能は変わってないので、2.9.xにあげるのを迷ってる方も同じようにserverMiddleware使えます。APIの定義方法パターン
Nuxt.jsの公式では、
// nuxt.config.ts serverMiddleware: [ { path: '/api', handler: '~/api/index.ts' }, ]ですが、私のスライドではこうなってたかと思います。
// nuxt.config.ts serverMiddleware: ['~/server'],nuxt.config.tsに一切APIのパスを書かず、全てexpress側で書くことができます。
たとえば// Nuxtからは叩かず、制御用のAPI /common/health // ロードバランサー用のヘルスチェックAPI /common/auth // 認証用共通API // アプリケーション用のNuxtから叩くAPI /api/hoge1 /api/hoge2こんな感じで、パスを分けた場合でもindex.tsのみの修正でOKです。
const router = Router() router.get('/health', (req: Request, res: Response | any, next: NextFunction) => { try { res.sendStatus(200) } catch (e) { next(e) } }) router.get('/auth', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// commonApi.ts const router = Router() router.get('/hoge1', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) router.get('/hoge2', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// src/server/index/ts import basicAuth from 'basic-auth-connect' import bodyParser from 'body-parser' import cookieParser from 'cookie-parser' import express from 'express' import dotenv from 'dotenv' import helmet from 'helmet' import session from './middleware/session' import commonApi from './commonApi' import appApi from './appApi' dotenv.config() const app = express() app.use(bodyParser.json()) app.use(cookieParser()) app.use(session()) app.use(helmet()) app.use(helmet.noCache()) // こういった感じでexpressでパスのルールを固定できます。 // これはexpress純粋の機能なので、nuxtには依存しません app.use('/common', commonApi) app.use('/api', appApi) module.exports = app派生パターンとしては、こういう風にパスの階層を元では持たせず、それぞれに任せることもできます。
// api.ts // commonApi.ts const router = Router() router.get('/api/hoge1', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// src/server/index/ts import appApi from './appApi' // 省略 app.use(helmet.noCache()) // パスの階層をここでは持たせず、それぞれに任せることもできます app.use(appApi)他にもパターンはいくつかありますが、expressの機能になりますので、より詳しく知りたい方はexpressのドキュメントをみると良いかと思います。
NuxtからAPIを実行する場合
Nuxtが動いているサーバーと同じところにAPIを作るので、Nuxtのページからaxiosを使ってリクエストする先が、自分自身になります。
Nuxt使ってる方はasyncData をよく使うと思いますが、本番運用する場合 nuxt.config.tsに設定を追加が必要になります。実際に設定する内容
// nuxt.config.ts /* ** Axios module configuration */ axios: { baseURL: 'http://localhost:3000', browserBaseURL: 'http://xxxxxx.com' // 自分のサイトのドメイン },なぜこうするかですが、nuxtのaxiosをみると、
prefix, host and port This options are used for default values of baseURL and browserBaseURL. Can be customized with API_PREFIX, API_HOST (or HOST) and API_PORT (or PORT) environment variables. Default value of prefix is /.とかいており、baseURLが
/になってしまいます。asyncDataは、SSRとSPAで動きますが、 SPAときは
/でもブラウザが解釈して自分自身の、
http://xxxxxx.com
にアクセスしてくれますが、SSRの場合は裏側のサーバーが自分自身にするので、ホスト名が入らないためアクセスできません。
nuxt.config.tsに明示的に指定することにより、
- SSR時は、baseURLにアクセスする
- SPA時は、browserBaseURLにアクセスする
という動きになりますので、devやstg環境などサーバーにdeployして利用する際は必要になります。
ご参考に
私のリポジトリの
https://github.com/tanaka-yui/nuxtjs-base-template
には、私が自作したAPIのvalidationをするミドルウェアや、Redisを使ったsession共有のミドルウェアなど(このへん)
実際にそのまま使えるものも入っております。こういう風に自前で作ったmiddlewareをAPIで利用できます
// JavaのSpringっぽく、バリデーション条件をchainするようになってます。 router.get( '/api/list'/, [ Authenticated, Validator([ new ValidatorItem('date').date(), new ValidatorItem('type').number().required(), ]) ], async (req: Request, res: Response | any, next: NextFunction) => { try { res.response(await services.getList(req)) } catch (e) { next(e) } } )expressなどのmiddlewareを自由に作れる様になると色々と便利になると思うのでご参考にしてみてくださいー
- 投稿日:2019-08-28T21:54:04+09:00
Nuxt.js+TypescriptでのserverMiddlewareの利用について(もう少し補足)
先日2019/08/26(月)に、NuxtMeetup#9で、
Nuxt.js+TypescriptでのserverMiddleware、のお話をさせていただきました。その時のスライドはこちらですー
Nuxt.jsのベストプラクティスを考えてみるもう少し、実践的な補足を記載しようかと思います。
私がよく使う自分でまとめたテンプレ
からちょっとソース抜粋してご説明します。テンプレはちょっと更新してないので、version 2.6.3ですが、この頃から serverMiddlewareの機能は変わってないので、2.9.xにあげるのを迷ってる方も同じようにserverMiddleware使えます。APIの定義方法パターン
Nuxt.jsの公式では、
// nuxt.config.ts serverMiddleware: [ { path: '/api', handler: '~/api/index.ts' }, ]ですが、私のスライドではこうなってたかと思います。
// nuxt.config.ts serverMiddleware: ['~/server'],nuxt.config.tsに一切APIのパスを書かず、全てexpress側で書くことができます。
たとえば// Nuxtからは叩かず、制御用のAPI /common/health // ロードバランサー用のヘルスチェックAPI /common/auth // 認証用共通API // アプリケーション用のNuxtから叩くAPI /api/hoge1 /api/hoge2こんな感じで、パスを分けた場合でもindex.tsのみの修正でOKです。
const router = Router() router.get('/health', (req: Request, res: Response | any, next: NextFunction) => { try { res.sendStatus(200) } catch (e) { next(e) } }) router.get('/auth', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// commonApi.ts const router = Router() router.get('/hoge1', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) router.get('/hoge2', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// src/server/index/ts import basicAuth from 'basic-auth-connect' import bodyParser from 'body-parser' import cookieParser from 'cookie-parser' import express from 'express' import dotenv from 'dotenv' import helmet from 'helmet' import session from './middleware/session' import commonApi from './commonApi' import appApi from './appApi' dotenv.config() const app = express() app.use(bodyParser.json()) app.use(cookieParser()) app.use(session()) app.use(helmet()) app.use(helmet.noCache()) // こういった感じでexpressでパスのルールを固定できます。 // これはexpress純粋の機能なので、nuxtには依存しません app.use('/common', commonApi) app.use('/api', appApi) module.exports = app派生パターンとしては、こういう風にパスの階層を元では持たせず、それぞれに任せることもできます。
// api.ts // commonApi.ts const router = Router() router.get('/api/hoge1', (req: Request, res: Response | any, next: NextFunction) => { try { // 必要な処理 res.sendStatus(200) } catch (e) { next(e) } }) export default router// src/server/index/ts import appApi from './appApi' // 省略 app.use(helmet.noCache()) // パスの階層をここでは持たせず、それぞれに任せることもできます app.use(appApi)他にもパターンはいくつかありますが、expressの機能になりますので、より詳しく知りたい方はexpressのドキュメントをみると良いかと思います。
NuxtからAPIを実行する場合
Nuxtが動いているサーバーと同じところにAPIを作るので、Nuxtのページからaxiosを使ってリクエストする先が、自分自身になります。
Nuxt使ってる方はasyncData をよく使うと思いますが、本番運用する場合 nuxt.config.tsに設定を追加が必要になります。実際に設定する内容
// nuxt.config.ts /* ** Axios module configuration */ axios: { baseURL: 'http://localhost:3000', browserBaseURL: 'http://xxxxxx.com' // 自分のサイトのドメイン },なぜこうするかですが、nuxtのaxiosをみると、
baseURLが
http://localhost:3000/になってしまいます。
URLの役割ですが、
- SSR時は、baseURLにアクセスする
- SPA時は、browserBaseURLにアクセスする
です。
asyncDataは、SSRとSPAで動きますが、ローカルでの開発の場合、SSR時もSPA時でもhttp://localhost:3000/なので自分自身を参照してるためアクセスできます。
productionやstaging環境などサーバーにdeployして利用する際は、何も指定していないと、SPAの時も、http://localhost:3000/api/hoge1のようになってしまいアクセスできません。なので、ブラウザの時に自分自身にアクセスできるようにbaseURL、browserBaseURLの指定が必要になります。また、CloudFront等のCDNを利用している場合は、baseURLをlocalhostにしてしまうとCDNを通らずAPIにキャッシュが効かないので、browserBaseURLと同じdomainをあえてbaseURLにいれて、CDN経由でAPIにアクセスするということもできます。
// nuxt.config.ts axios: { baseURL: 'https://xxxxxx.com', // 両方とも同じにして、SSR時もCDN経由させる browserBaseURL: 'https://xxxxxx.com' },ご参考に
私のリポジトリの
https://github.com/tanaka-yui/nuxtjs-base-template
には、私が自作したAPIのvalidationをするミドルウェアや、Redisを使ったsession共有のミドルウェアなど(このへん)
実際にそのまま使えるものも入っております。こういう風に自前で作ったmiddlewareをAPIで利用できます
// JavaのSpringっぽく、バリデーション条件をchainするようになってます。 router.get( '/api/list'/, [ Authenticated, Validator([ new ValidatorItem('date').date(), new ValidatorItem('type').number().required(), ]) ], async (req: Request, res: Response | any, next: NextFunction) => { try { res.response(await services.getList(req)) } catch (e) { next(e) } } )expressなどのmiddlewareを自由に作れる様になると色々と便利になると思うのでご参考にしていただけるとー
- 投稿日:2019-08-28T21:26:10+09:00
個人的にwebスクレイピングでよく使うメソッド(Javascript)
備忘録としてNode.jsでWebスクレイピングをする際に個人的によく使うメソッドをまとめておく。
前処理編
filter
配列にフィルターを施す。
任意の条件に対して返り値がtrueであった値のみ出力される。
外部ファイルからデータを読み込むようにしていたため、不正なURLやパラメータが記載されていた場合は排除するようにしていた。example.jsvar urlList= ["https://example.co.jp/item", "https://example.co.jp/list", "https://exmple.co.jp/user"]; var filteredUrlList = urlList.filter(url => url.includes("https://example.co.jp")); console.log(filteredUrlList ) // Array ["https://example.co.jp/item", "https://example.co.jp/list"]splice
配列から指定した値を削除したり追加したりする。
filterと似たような使い方をしていたため、どちらかというと配列内のデータを削除したいときに使う。toLowerCase & toUpperCase
対象の文字を大文字もしくは小文字に変換する。
外部ファイルから読み込んだデータをURLのパラメーターとして使う際によく置換していた。データ加工編
replace
対象の文字を指定した文字に変更できる。
正規表現と組み合わせて余分な空白を削除したり日付を任意のフォーマットに変更するときによく使う。example.jsvar date = "2018/02/21"; var modifiedDate = date.replace(/\/,-g/, "-"); console.log(modifiedDate) // "2018-02-21"substring & substr
対象の文字列から指定したインデックスの文字を取得する。
substringは 第二引数は終了地点であるのに対し、substrは取得文字数を意味している。
**example.jsvar date = "2018/02/21 12:32"; var modifiedDate = date.substring(0, 10); console.log(modifiedDate) // "2018/02/21"【追記】
確認すると、どうやらsubstrは非推奨とまではいかないものの、できるだけ使用は避けるべきと公式に記載がされている。出力編
push & contat
指定したデータを配列の一番後ろに追加することができる。
pushを使うとpushされる前のデータはなくなる(破壊的結合)が、contatを使うとその前のデータは保持される(非破壊的結合)という違いがある。
Webスクレイピングで取得したデータを出力対象に追加する際に使う。example.jsvar items = ["a", "b", "c", "d"]; // So Many Data var newItem= "e"; items.push(newItem); console.log(items); // Array ["a", "b", "c", "d", "e"]slice
配列もしくは文字列から指定した範囲を抜き取る。
spliceとは異なり、以前のデータは破壊されない。
取得したデータを分割して出力する際に使うexample.jsvar items = ["a", "b", "c", "d", "more"]; // So Many Data for (i=0, i*50 >item.length, i++) { var list= date.slice(i*50, (i+1)*50); console.log(list) // "50件ずつ出力" };
- 投稿日:2019-08-28T21:04:13+09:00
LINEのMessaging APIからのデータをBeebotteに垂れ流すNode.jsサーバ
はじめに
※この投稿は、LINEのメッセージをGoogle Homeで読み上げる(機能強化版)を実装済みで更に機能強化を求む人向けの投稿です。
LINEのメッセージをGoogle Homeで読み上げる(機能強化版)を使って、個人的に機能強化も加えたりして遊んでいたんですが、ついにMicrosoft flowの無料で750回のAPIコール/月の上限に達しました。
むしゃくしゃして課金しようとしたんですが、
- アカウント作るのに独自ドメインのメールアドレスが必要
- USD $5.00/月と、個人で楽しむにしては高いコストがかかる
ので、やっぱりむしゃくしゃしてLINE Messaging APIからのWebhook呼び出しをBeebotteに垂れ流すnodejsサーバを書きました。っていう話。
この話を理解するには以下の知識が必要になります。
- nodejsの使い方
- かんたんなサーバ・クライアントの知識
- Glitchの基礎知識。(以下をどうぞ)
- [Node.js] 無料で簡単にウェブアプリを公開できるサービス「Glitch」を使ってみた!
- ThimbleからGlitchへ移行する方法と注意点!+ Glitchってどんなサービス?【ざっくりまとめ】
- 簡単に言うと、nodejsがかける無料サーバだよ!無料だからちょっと制限あるけど、開発や小規模APIを作るならもってこい。
特徴・できること
- LINE Messaging APIからのWebhook呼び出しをBeebotteに垂れ流すサーバ
- 「LINEのWebhookリクエストの内容は{events:[{<メッセージ内容>}]となっていますが、BeebotteのREST APIは{data:{}}の形式しか受け付けない」ため、要素名を書き換えてBeebotteに送りつけるサーバ。
- Mcrosoft Flowの無料750回APIコール/月を突破し、4000回/時のアクセスまでできる。およそ月に約28万アクセスできる計算。どのご家庭にもあるbot込の家族lineグループなら安心の帯域量!
- Mcrosoft Flowのときはチェックしていなかった、
X-Line-Signature(LINE developersを参照)を検証する。確実にLINEサーバからのメッセージしか通さない。ソースちょーだい
プロジェクト自体は、githubで公開しています。※ただ、まだ動くだけの書き捨てコード状態。
インストール手順
Glitchで新規プロジェクトを作成。
# npm i crypto body-parserで必要なパッケージをインストール。.envにLINEのCHANNEL_SECRETとBEEBOTTEのTOKENを書いて、server.jsもコピペする。
LINE_CHANNEL_SECRET='[SECRET]' BEEBOTTE_TOKEN='[TOKEN]'server.jsconst express = require('express'); const crypto = require("crypto"); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json({verify: function (req, res, buf, encoding) { function validate_signature(signature, body) { const LINE_CHANNEL_SECRET = process.env.LINE_CHANNEL_SECRET; return signature == crypto.createHmac('sha256', LINE_CHANNEL_SECRET).update(body).digest('base64'); } //test signature if (!validate_signature(req.headers['x-line-signature'], buf)) { throw new Error('Invalid signature.'); } }})); //リクエストがあったら応答 app.post('/api/lineToBeebotte', function(req, res, err) { const events = req.body.events; const resJson = { data: req.body.events }; const request = require('request-promise'); console.log(resJson); request({ url: 'https://api.beebotte.com/v1/data/publish/line/message?token=' + process.env.BEEBOTTE_TOKEN, method: 'POST', form : resJson }).then(()=>{ res.json({result:'sucsess'}); }).catch(()=>{ res.json({result:'fail'}); }); }); const listener = app.listen(process.env.PORT, function() { console.log('Your app is listening on port ' + listener.address().port); });LINEのコンソールに設定する
LINEのデベロッパツールの中のコンソールに入り、
Webhook URLにhttps://youredoamin.glitch.me/api/lineToBeebotteを設定する。※youredoaminは置き換えまとめ
以上、ただ、垂れ流すだけのサーバですが、nodejsの勉強になって楽しかったです。ただ、朝4時までかけて突貫工事ですることではなかった←
- 投稿日:2019-08-28T18:54:22+09:00
分からねえ!!
Node.jsをインストールしたはいいが、おかしい。
$ npm install -g vue-cli
って打ち込んでEnterしたら
npm ERR! code ENOTFOUND
npm ERR! errno ENOTFOUND
以下略。。って表示が出て何やらできてないっぽい。。。
なんだ?国会図書館のWifi使ったからか?そこのあなた助けてくだざい。。。
(追記)
家のwifi繋いだら無事できました。
見てくれた皆さまお騒がせしてすいません。
ありがとうございました。
- 投稿日:2019-08-28T02:21:51+09:00
nodejsプロジェクトをgulpでDropboxにバックアップする
要約
nodejsを使った開発環境でバージョン管理じゃなくて単なるバックアップとしてソースコードを管理する方法を検討しました。
※この記事の対象読者:
nodejsのプロジェクトでタスク管理にgulpを利用している人で、バージョン管理以外でバックアップとしてソースコード管理をしたい人問題点
- node_modulesとか.gitとかdistとかを同期したくない
- 主要なクラウドサービス(Dropbox, GoogleDrive, iCloud)は特定のファイル・ディレクトリを同期から除外するための設定が若干めんどくさい、または存在しない。
解決方法
- gulpを利用してビルドのたびにバックアップディレクトリにソースファイルをコピーする。
- 基本的にプロジェクト全体をバックアップするが、gulpの設定で特定のディレクトリはコピーの対象から外す。
背景
昨日SSDが逝きました。
リモートリポジトリにはまだpushしてなかったコード達がお亡くなりになりました。
バージョン管理とバックアップは別物なんだなぁ
みつを
本当にありがとうございました。(主にMacを使ってるので)昔はTimeMachineでバックアップを取ってたのですが、NASが壊れたのを機にそのまま放置してしました・・・。
自前でバックアップとるのはもう嫌なので、手軽にクラウドでバックアップを取る方法を調べて検討したのでメモします。
本当はもっと賢い方法があるのでしょうが、わからないので誰かご存じでしたら教えていただけると助かります・・・。
従来手法?
Dropbox
.gitignoreっ的なもので制御
dbignoreというOSSがあるけどMacしか対応してない(多分)。
(たまにWindowsも使うんじゃ・・・T^T)
http://konolige.com/dbignore/公式も「たくさん要望あるけどまだ作れてござらん」っておっしゃってる?
https://www.dropboxforum.com/t5/Files-folders/Exclude-specific-folder-names-with-Smart-Sync/td-p/289837GUIで制御
selective syncという設定をすることで、ディレクトリを一つ一つ同期するかしないかを選択できる?らしいけど、これやるとローカルからディレクトリが消されるので開発できないorz。重たいファイルを特定のデバイスにダウンロードさせないための機能っぽい。
https://help.dropbox.com/installs-integrations/sync-uploads/selective-sync-overviewGoogleDrive
GUIで制御
drop boxと同じでローカルから削除されるっぽい(未検証)
https://support.google.com/drive/forum/AAAAOxCWsTozRU34aolkdo/?hl=en&gpf=%23!topic%2Fdrive%2FzRU34aolkdoiCloud
ファイル名で制御
ファイル末尾に.nosync または.tmpをつける。
これは仮にできたとしても、やりたくないので未検証・・・
https://discussions.apple.com/thread/8137146OneDrive
ない
「OneDriveの思想はOneDriveの中身すべてを同期させることやぞ」
「特定のディレクトリを除外する機能を作るとしてもNot Right Nowだ」とのこと(2015年)従来手法のまとめ
クロスプラットフォームで簡単に開発中のものをバックアップするような主要なクラウドサービスはない(多分。ほんとか?)。提案手法
Gulp(v4)でビルドするたびにどっかにコピーする。
下準備
バックアップディレクトリの定義
(1人/1つの開発マシンしかないならこれをやらずにgulpfile.jsにパスをべた書きでOK。)
mac/linuxだったら単にterminalで、windowsだったらgitbashで下記を.bashrcとかに追記※gulp
https://gulpjs.com/EXPORT backup_directory="/backup/directory"gulpfile.jsに設定を追加
var gulp = require('gulp'); var path = require("path"); gulp.task('backup:src', function () { return gulp.src([ './**', //コピーしたいファイルのパス '!./node_modules/**', //除外したいパス(先頭に!をつける) '!./dist/**', //同上 '!./.git' //同上 ]) .pipe(gulp.dest(process.env.backup_directory+'/'+path.basename(__dirname))); //back_updirectory/projectname配下にバックアップ }); gulp.task('default', gulp.series( //ほかのタスク:コンパイルとかデプロイとか 'backup:src', //... ) );タスクを実行
npx gulp結果
Mac死んでるからWindowsで検証してる・・・orz結論
gulpを使えば、ビルドの度に手軽にソースコードをDropboxにバックアップでき、node_modulesなどは除外できました。多分他のクラウドサービスも同じように実行できると思います。
まとめと感想
初めてQiita記事を書いてみました。
間違いなどあれば、ご指摘いただけると助かります。本当に簡単にソースコードバックアップできるサービスないのかな。。。
Javaとか他の開発環境には適用できないし、いっそすべての言語のプロジェクトをGulpでタスク管理するか・・・。と思ったけどそれは違う気がする。
- 投稿日:2019-08-28T00:33:11+09:00
簡単にhttps化できる「あ、このテストhttps対応してないとできないテストやん!」って時に使えるものを作りました
あ、このテストhttps対応してないとできないテストやん!って時に使えるものを作りました
コードをいじりたくない時に使ってください
このレポジトリで見てください
https://github.com/takashiAg/https_easiest_proxy経緯
streamingAPIとか使用する場合、その他テストをするときにhttps対応してないとできなかったりする。
選択肢としては、
- テスト用にhttps対応コードをかく
- 本番環境へのケースの切り分けが面倒
- 詳しくやり方がわからない
- Apacheやnginxでリバースプロキシを設定する
- 証明書の発行
- httpsに対応するようapacheインストール
- 設定ファイルの作成
が必要になるますが、面倒ですよね。
WAN=80 LAN=3000 node proxy.jsと書けば、プロキシとして動作するものを作りました。(bash)installation
git clone https://github.com/takashiAg/https_easiest_proxy cd https_easiest_proxy npm install openssl genrsa 2048 > mysslserver.key openssl req -new -key mysslserver.key -subj "/C=JP/ST=Tokyo-to/L=Shibuya/O=Company Name/OU=IT dept./CN=Company Dept CA" > mysslserver.csr openssl x509 -days 3650 -req -signkey mysslserver.key < mysslserver.csr > mysslserver.crt openssl pkcs12 -export -inkey mysslserver.key -in mysslserver.crt > mysslserver.pfxstart
node proxy.jschange port
WAN=80 LAN=3000 node proxy.js
