Express v4.xでJSONのリクエスト/レスポンスを取得する正しい方法

ExpressでJSONのリクエストを受け付けて、JSONのレスポンスを返す処理のメモです。

たまにExpressで検証などすることがあるのですが、いつもJSONの扱い方を検索している気がするので自分でもまとめておくことにしました。

また、検索するとbody-parserをインストールするように書かれている記事が多いのですが、2020年5月現在はExpress本体にミドルウェアが用意されています。
よって、以下の方法がおそらく現在最もシンプルで標準的な手順になると思います。(公式マニュアル読めばいいという話でもありますが)

Expressについて

自分はこれまでなんとなくExpressを使っていたので改めてまとめてみました(ご存知の方は飛ばして下さい)。

Expressは、node.jsのWebフレームワークですが、Webフレームワークと言ってもPHPのDjangoやRubyのRailsのようなフルスタックのフレームワークではなく、PythonのFlaskやRubyのSinatra、PHPであればLaravelではなくSilexなどにあたり、他の言語だと軽量フレームワーク相当のものです。

具体的に以下の機能を提供しています。

  • HTTPリクエスト/レスポンスの処理
  • ルーティング
  • ミドルウェア: LaravelのミドルウェアやRailsのフィルタにあたります
  • 静的ファイルの配信
  • プロジェクト生成コマンド

テンプレートはデフォルトでは入っていないので、必要に応じて追加します。
(参照: Express でのテンプレート・エンジンの使用)

事前準備

ここから本題、まず確認用のプロジェクトを作成します。

$ mkdir express-json-sample && cd express-json-sample
$ npm init -y
$ npm install express --save

リクエストボディのJSONを受け取る

ところで、Expressのリクエストボディをreq.bodyで取得しようとしてもundefinedで、はじめて使うと「?」となります。

これについては「API リファレンス req.body」に
「By default, it is undefined, and is populated when you use body-parsing middleware such as express.json() or express.urlencoded().」と記載されているとおりデフォルトの動作で、適当なbody-parserの使用を宣言する必要があります。

記事冒頭で書いたとおり、4.x系ではbody-parserのインストールは不要で、JSONをパースするミドルウェアexpress.json()が用意されています。

以下のように、express.json()app.useに指定します。

const express = require('express')
const app = express()
app.use(express.json())

app.post('/', function (req, res) {
  console.log(req.body);
  res.send('Got a POST request')
})

app.listen(3000, () => console.log('Example app listening on port 3000!'))

curlで動作確認

$ curl http://localhost:3000 -X POST -H "Contion/json" -d '{"name":"鈴木一郎", "age":55}' 

ターミナル側の出力は以下の通り、ちゃんとパースされたオブジェクトを確認できます。

$ node app.js 
Example app listening on port 3000!
{ name: '鈴木一郎', age: 55 }

レスポンス

レスポンスのボディにJSONを返す場合は、res.json([body])メソッドを使用します。
res.jsonメソッドは、ヘッダーにContent-Typeapplication/jsonを追加、オブジェクトをJSON.stringify()して返してくれます。

上記のコードを以下のように書き換えます。

app.post('/', function (req, res) {
  console.log(req.body);
  res.json({'msg':'Got a POST request'});
})

curlで実行確認、レスポンスヘッダーも出力してみます。

$ curl http://localhost:3000 -X POST -H "Contention/json" -d '{"name":"鈴木一郎", "age":55}' -D -
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 28
ETag: W/"1c-/EdmnxF6KOt7WkTBgbBDKhXsS7U"
Date: Sat, 30 May 2020 00:04:11 GMT
Connection: keep-alive

{"msg":"Got a POST request"}

その他参考情報

記事を書いている際に調べたことをついでにメモしておきます。

通常のフォームリクエストのボディ

Content-Typeapplication/x-www-form-urlencodedのケースです。
express.urlencodedミドルウェアをセットすればOKです。

const express = require('express')
const app = express()
app.use(express.urlencoded({ extended: true }))
app.post('/', function (req, res) {
  console.log(req.body);
  res.send('Got a POST request')
})

動作確認

$ curl -X POST http://localhost:3000 -d 'name=鈴木一郎&age=55'

ターミナル側の出力、パラメータをオブジェクトに変換して取得できます。

$ node app.js 
Example app listening on port 3000!
{ name: '鈴木一郎', age: '55' }

調査中に試した他のレスポンス ボディの返し方メモ

Proper way to return JSON using node or Express

var http = require('http');

var app = http.createServer(function(req,res){
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ a: 1 }, null, 3));
});
app.listen(3000);

Vue.js x TypeScriptのプロジェクトでjQuery UIを使う

以前の記事「React x TypeScript x Webpackの開発環境でjQuery (Bootstrap)を使うには」のVue.js x TypeScript版になります。

改めて調べた背景としては、Vue x TypeScriptのプロジェクトで、ある要素をドラッグしてただ移動するという機能をHTML5のDrag and Drop APIを使って実装しようとしたところ、ただの移動を実装するのは意外と面倒でした。そこで、昔ながらのライブラリの導入を検討してみるかと思いつき試したところです。

jQuery UI以外の候補としては、interactjsあたりがパッケージ内に型定義も含んでいて良さそうでしたが残念ながらコンパイルが通らずその修正は大変そうだったので、結局一番使われていて型定義もしっかりしていそうなJQuery UIを試してみることにしました。

この記事のサンプルはGithub hrendoh/vue-ts-jqueryui-example にアップしていますので参照ください。
動作については記事本文の最後にgifアニメを貼っていますが、箱を追加して移動できるというシンプルなサンプルです。

プロジェクトの作成

Vue CLIで、TypeScriptを使用するように設定し、その他はなしで作成したプロジェクトに設定していきます。

vue cliでtypescriptのプロジェクトを作成

その他設定は以下の通り。

jquery jquery-uiのインストール

$ npm install jquery jquery-ui --save
$ npm install @types/jquery @types/jqueryui --save-dev

TypeScriptのコンパイラーオプションのpathsにjquery-ui用の型定義ファイルを指定します。

// tsconfig.json
{
  "compilerOptions": {
    ...
    "paths": {
      "@/*": [
        "src/*"
      ],
      "jquery-ui": [
        "node_modules/@types/jqueryui/index"
      ]
    },
    ...

あとは、jQuery UIを使う箇所で以下のようにimportすればOKです。

import $ from "jquery";
import "jquery-ui";

サンプルではcomponents/Box.vueの12行目でimportしています。

jquery jquery-uiのソースの読み込み

ここまでの設定は、TypeScriptのコンパイルを通すところまでで、実際に動かすにはjQueryとjQuery UIのソースをビルド後のファイルapp.xxxx.jsに含める必要があります。

まず、npmパッケージjquery-uiにはビルド前のソースのみ含まれていないため、ビルド済みのソースを含むjquery-ui-distを追加でインストールします。

$ npm install jquery-ui-dist --save

追加したjquery-ui-distのソースをバンドルするWebpackの設定はVueプロジェクトの設定ファイルvue.config.jsに記述します。

vue.config.jsファイルはVue CLIを作成したプロジェクトにはデフォルトで含まれていないので作成して以下の記述を含めます。

// vue.config.js
const path = require("path");
module.exports = {
  configureWebpack: {
    devtool: "source-map",
    optimization: {
      minimize: false
    },
    resolve: {
      alias: {
        // bind version of jquery-ui
        "jquery-ui": "jquery-ui-dist/jquery-ui.js",
        // bind to modules;
        modules: path.join(__dirname, "node_modules")
      }
    }
  }
};

再度ビルドすると、dragableがちゃんと動くことを確認できます。

jQuery UIによるドラッグの実装

課題 VSCodeの補完ができない

“jquery-ui”は、型定義が”jqueryui”と名前が合っていないため、VSCodeの補完とエラーが解決できません。

VSCodeでjquery-uiの型が参照できない

おそらく設定で解決できるのではと思いますが、未調査です。

ちなみに、”jquery-ui”ではなく”jqueryui“をインストールするとちゃんとVSCodeの補完も効きますが、公式があるのにそちらを使う気にはなれないのでVSCodeの設定を調べる方が正攻法かなとは思います。

参考

以下の記事は簡潔にまとまっていて参考になりました。

【TypeScript】外部ライブラリ(jQueryなど)を使用する方法をまとめてみる

あとはこのあたり

Error when using JQueryUI with TypeScript and DefinitelyTyped definition file

Laravel 6.x laravel/uiを利用してbootstrap 4を適用する

Laravel2 Advent Calendar 2019 – Qiita の15日目の記事になります。
(ちょうど空いていたのでぎりぎりですが参加させていただきました。)

Laravel 5.8以前ではフロントエンド フレームワークとしてbootstrapとVueがはじめから利用可能なように設定されていましたが、Laravel 6.xではデフォルトでは含まれなくなりました。

6.xでBootstrapを利用するには、フロントエンドのScafolding機能を提供するlaravel/uiのコマンドを使用してJavascriptのビルドとCSSのプリプロセッサ設定を生成する必要があります。

この記事では、Laravel 6.xのプロジェクトにlaravel/uiを利用してBootstrapをプロジェクトに導入する手順についてシンプルなアプリケーションを例に解説しています。
想定しているケースは、主にサーバー側のビューテンプレートで画面を実装する場合に、アプリケーション全体でBootstrap 4の基本的な機能を使ってマークアップと多少画面の動きをつけたい(DatePickerを利用したいなど)といった構成のアプリケーションです。
本格的にフロントエンド開発の環境を整えるには、Laravel Mixについても学ぶ必要がありますが、デフォルトのwebpack.mix.jsの設定でできる範囲にとどめて深堀りしません。

この記事のサンプルソースは Github リポジトリ https://github.com/hrendoh/laravel-ui-bootstrap-tasks に公開しています。記事の中で解説していないソースコードについてはこちらを参照ください。
“Laravel 6.x laravel/uiを利用してbootstrap 4を適用する” の続きを読む

LaravelのセッションをHeroku Redisに保存する

LaravelアプリのセッションをHeroku Redisに保存する設定する手順についてまとめてみます。

HerokuでRedisを利用する場合、現在(2019.11)は公式のHeroku Redisを利用できます。

公式ドキュメントはこちら: Heroku Redis | Heroku Dev Center

セッションをキャッシュに入れるのはなぜか?

ところで、改めてHerokuでセッションをRedisなどのストレージに保存する必要があるのか?ってことなんですが、試しにfree Dynoを使っていてすぐにDynoがsleepしてしまうような場合は、DynoのファイルシステムはEphemeral Disk(揮発性ディスク)なのでRedisなどに保存しておかないとsleepするたびにセッションが切れてしまいます。
また、Hobby以上のDynoの場合でも1日一回は再起動されるとのことなのでやはりキャッシュストレージに入れておいた方が良さそうです。
参照: Restarting | Dynos and the Dyno Manager

一方、1日1回くらいならまあいいかとしてDynoが複数の場合はでは必要なのか?って話ですが、セッション固定機能のSession Affinityを使えば問題ないかもしれません。
“LaravelのセッションをHeroku Redisに保存する” の続きを読む

HerokuにデプロイしたLaravelアプリのアセットのURLをhttpsにする手順

HerokuではSSLの処理をロードバランサーで行っているので、Dyno上のLaravelアプリケーションはデフォルト設定ではhttpで動いていると判定されアセットのURLがhttpになってしまします。

そのまま表示すると以下のようにブラウザの警告が出てしまいます。

Herokuのロードバランサーまわりについては、公式ドキュメントのHTTP Routingで説明されています。

Laravelで、ロードバランサー経由のhttpsリクエストを判定するには、公式ドキュメント「HTTP Requests」の「Configuring Trusted Proxies」の「Trusting All Proxies」に記述されている通りApp\Http\Middlewar\TrustProxiesクラスのproxiesの値にロードバランサーのIPアドレスをセットします。
Herokuの場合、そもそもロードバランサーのIPアドレスは判らないのですし、Web DynoにはグローバルIPアドレスは割あたってない(はず)ので、すべてのプロキシからのリクエストを信頼する「*」をセットします。

“HerokuにデプロイしたLaravelアプリのアセットのURLをhttpsにする手順” の続きを読む

Laravel 6.0 on Heroku mailgun アドオンでメール送信実装手順

Laravel 6.0では、3rdパーティのメール送信サービスMailgun, Postmark, Amazon SESが標準で選択できます。バージョンによっては、MandrillやSparkPostもサポートしていたようです。Transportのクラスは残っているので設定すれば使えるかもしれません。

一方、この記事を書いている2019年10月時点でHerokuアドオンとして利用可能なメールサービス(SMS含む)のラインナップは以下の通りです。

よって、Laravel 標準サポートで、Herokuのアドオンとして利用可能なサービスはMailgunのみとなります。
“Laravel 6.0 on Heroku mailgun アドオンでメール送信実装手順” の続きを読む

Laravel 6 でCSV出力を実装する(レスポンスストリームにそのまま返す版)

LaravelでCSV出力を実装してみたので手順をまとめます。

動作確認はLaravel 6でしていますが、この記事の内容は5.6以降で利用可能です。

CSVのサイズが大きくなる場合は、コントローラはCSV生成タスクをバックグラウンドキューに入れて非同期ジョブでCSVを生成してS3などのストレージに追加、処理が完了したらファイルのURLを応答に含めて通知するというのが正しい実装な気がしますが、ここではCSVに含めるレコードが少なくファイルサイズが小さめな限定的なケースを想定し、CSVを生成しながらそのまま応答ストリームに流すような実装について解説します。

小さめと書きましたが、プロセスのメモリーを節約して実行するのでネットワーク環境と多重度が低くプロセスを長めに専有することを許容できるシステムであれば大量レコードでも使えるのでプロジェクトによっては大量レコードのダウンロードにも使える仕組みとなっています。

利用するLaravelフレームワークの機能を整理

まずサンプル実装に使うLaravelの機能について解説してみます。

ストリームを応答として返す

大容量のファイルをストリームで帰す場合は、streamDownloadメソッドを利用します。streamDownloadメソッドは、Laravel 5.6から導入されたメソッドです。

Laravelのドキュメント HTTP ResponsesのFile Downloads Streamed Downloads で説明されています。
“Laravel 6 でCSV出力を実装する(レスポンスストリームにそのまま返す版)” の続きを読む

Heroku SchedulerでLaravelのartisanコマンドを実行する

LaravelのartisanコマンドをHeroku Schedulerを使って、定期実行する手順に確認したのでまとめてみました。

Laravelのバージョンは、2019年9月時点での最新6.0で確認しています。

Heroku Schedulerのとは

Heroku Schedulerは、cronジョブ的な仕組みを提供するHeroku公式アドオンです。

ドキュメントによると実行間隔は10分、1時間、1日のみです。
この要件で問題なければ非常に便利な機能です。

実行時刻は正確ではないので、ジョブを正確な時刻に実行する必要がある場合はここで説明するSchedulerではなくCustom Clock Processを利用する必要があります。

また、Heroku Schedulerジョブで実行するタスクの実行時間について「Long-running jobs」には、実行時間が数分を超えるような長いタスクを実行する場合は、バックグラウンドキューに入れてワーカーDynoでタスクを実行するべきと書いてあります。
更に、スケジューラーで起動されたDynoは、次のスケジュール実行時間になると停止するとも書いてあります。
よって、基本的にはLaravelの場合QueuesをワーカーDynoで起動しておいて、スケジュールジョブではジョブをディスパッチするのみにするのが正しい実装になります。

しかし、この記事では、まずはHeroku Schedulerの動作の雰囲気を掴むため、Heroku Schedulerのジョブからシンプルなartisan commandを直接実行して動作を確認してみます。
“Heroku SchedulerでLaravelのartisanコマンドを実行する” の続きを読む

HerokuでLaravel 6のログをPapertrailに出力する

HerokuにデプロイしたLaravelアプリケーションのログメッセージをHerokuのログシステムに出力して、Papertrailに連携する手順と説明をまとめました。

Laravelのバージョンは、2019年9月時点での最新6.0で確認しています。

LaravelのログをHerokuのログに統合する

PHP Application Logging | Heroku Dev Center」によると、Herokuのログ管理システム(Logplexという)はstdoutおよびstderrに出力されるメッセージをログストリームとして集めます。

heroku logsコマンドで確認できるログメッセージは各Dynoからここに集められたログを見ているわけです。

そこで、Laravelの場合もstrerrにログが出力されるように設定します。
Herokuのドキュメントの「Laravel」に記載されている通り、環境変数LOG_CHANNELerrorlogをセットするだけでOKです。

環境変数LOG_CHANNELerrorlogをセットするコマンドは以下のとおり

$ heroku config:set LOG_CHANNEL=errorlog

“HerokuでLaravel 6のログをPapertrailに出力する” の続きを読む

Laravel Socialite でMicrosoft Graph (Office 365アカウント)認証する

前回の記事 「Laravel 5.8からMicrosoft Graph APIを利用する (公式ドキュメント編)」では、Micsoroft公式のチュートリアル ドキュメントに沿って、LaravelアプリケーションからMicrosoft Graph APIをOAuth認証プロバイダとして利用する手順について確認しました。

このチュートリアルは、OAuthの認証ロジックをleague/oauth2-clientを使って独自に実装していましたが、実際はLaravel公式のOAuth認証パッケージLaravel Socialiteを使いたいところです。

Laravel Socialiteは非常に多くの認証プロバイダーに対応しています。対応プロバイダーは、Socialite Providersで確認できます。
Microsoft Graphについてももちろん対応しています。

この記事では、Laravel Socialiteを利用してAzure ADのアカウントで認証を実装する手順について確認します。
Auth Scaffoldは使わず、つまりデータベース認証は使わずに、OAuth認証後にLaravel標準のAuthユーザとしてログインし、Auth middlewareを使って要認証のルーティングを保護する手順についても説明しています。

この記事に含まないこと

Azure ADに登録されたアカウントによる認証にのみフォーカスして説明しています。
Microsoft Graph APIを利用したデータの取得については説明しません。
よって、アクセストークンの更新についても言及していません。
“Laravel Socialite でMicrosoft Graph (Office 365アカウント)認証する” の続きを読む