Node.jsからExpressへファイルのアップロードを処理する方法
読む所要時間: 10 分
最近、Node.jsでMarkdownでの記事執筆のためのCLIツールを開発していました。ローカルの.mdファイルを解析して、書式設定し、.docxに変換してから、Google DocファイルとしてGoogleドライブにアップロードするというもので、このすべてをターミナルから1つのコマンドで実行します。
いくつかの方法でこのプロジェクトにアプローチしてみましたが、最初はサーバーレス関数を使用してバックエンドを処理できると考えました。この方法では何度も行き詰まり、最終的にHerokuにホストするExpressサーバーを構築することにしました。
CLIからセキュアなバックエンドのエンドポイント(ユーザーの認証済みGoogleドライブ)に.docxファイルの内容をアップロードするには、ブラウザを使用せずにNode.jsから直接multipart/form-data
をPOST
する方法が必要でした。これにはいくつかのサードパーティのライブラリが必要ですが、それらをすべて連携させることは困難でした。役に立つ優れたリソースをインターネットで見つけることはできず、多くの試行錯誤を繰り返しました。この記事では、これを実現するにあたってたどり着いたNode.jsからExpressへファイルをアップロードする方法をご紹介します。
必要条件
このチュートリアルには、以下の項目が必要です。
アプリケーションの構造を設定する
ターミナルまたはコマンドプロンプトで、一般的なプロジェクトまたは開発用ディレクトリに移動し、次のコマンドを実行します。
これらのコマンドで、Node.jsアプリケーションとExpress APIの両方のプロジェクトを保持するディレクトリを作成します。また、Expressバックエンドの雛形をexpress-generator
で作成し、必要な依存パッケージを新しいExpressアプリケーションにインストールします。
Node.jsアプリケーションの雛形を作成する
ターミナルで、親ディレクトリのmultipart-demoに戻り、Node.jsアプリケーションに移
動して、次のコマンドを実行します。
新しいNode.jsアプリケーションを初期化します。
このプロジェクトに必要なサードパーティの依存パッケージをインストールします。
form-data
ライブラリを使用して、キーと値のペアが含まれる「フォーム」をNode.jsアプリケーションに作成します。ExpressアプリケーションにフォームデータをPOST
するには、axios
を使用します。
コードを記述してファイルをアップロードする
テキストエディタを使用し、node_appフォルダのindex.jsファイルを新規作成し、開きます。このファイル内で、次のコードを上部に追加します。
このコードでは、インストールした2つのサードパーティの依存関係をインポートし、ファイルシステムと対話できるようにするfs
モジュールをインポートします。
これらの行の下に、次の関数と関数呼び出しを追加します。
upload()
関数は非同期関数です。関数内にはtry/catch
ブロックがあります。これは、関数がtry
ブロック内で処理の実行を「試行」することを意味します。コードにエラーが発生した場合は、catch
ブロックをすぐに実行し、そこで問題のエラーにアクセスできます。
try
ブロックで最初に試行することは、file
とtitle
の2つの変数を作成することです。
3行目(file
変数が作成されている)がハイライトされていますが、これは、表示されているファイルパスを、アップロードするファイルのパスに置き換える必要があるためです。この変数は、ファイルの読み取り可能なストリームを表します。
title
変数では、アップロードするファイルのタイトルを保存しますが、任意の文字列値に変更できます。
これらの変数の下に、フォームが作成されます。ファイルとそのタイトル用の2つのキーと値のペアがフォームに追加されます。このように、フォームデータを表す任意の数のキーと値のペアをform
オブジェクトに追加できます。
次に、axios
を使用して、フォーム全体がExpressバックエンドにポストされます。フォームをポストするエンドポイントはチュートリアルの後半で作成します。ヘッダー情報でオプションのオブジェクトをaxios.post()
メソッドに渡すことに注意してください。form-data
ライブラリでは、フォームデータに適したヘッダーを返す.getHeaders()
メソッドを指定して、ヘッダーを簡単に正しく設定できます。
エラーがない場合は、「Upload complete」のメッセージがコンソールに記録されます。それ以外の場合は、エラーメッセージがログに記録されます。
フォームデータを処理する
ファイルを正常に送信したら、バックエンドで処理できるようにする必要があります。
ターミナルで、Expressアプリケーションに移動します。
Multerは、multipart/form-data
を処理するNode.jsミドルウェアです。次のコマンドを実行し、multer
パッケージをインストールします。
テキストエディターから、multipart_demo/express_app/routesフォルダにあるindex.jsファイルを開きます。ファイルの内容を削除し、次の内容に置き換えます。
このコードでは、注意することがいくつかあります。特に重要な行はハイライトされています。
5行目では、multer
パッケージがインポートされた後に、multer()
関数を呼び出して、dest
キーを持つオプションオブジェクトを渡し、返されたオブジェクトをupload
変数に保存して、Multerを使用する準備をしています。ディスクではなくメモリにファイルを保存するなど、Multerを設定する他の方法については、ドキュメントを参照してください。
この場合、Multerではアップロードしたファイルを別の場所に保存する必要があるため、dest
値を指定しています。このアプリケーションでは、ファイルが一時的に必要なため、保存先をサーバーの/tmpフォルダに設定します。アップロードしたファイルを保持する必要がある場合、このオブジェクトのパスを指定すれば、サーバーの別のディレクトリに保存できます。
7行目では、APIエンドポイントのコールバック関数を実行する前に、upload
オブジェクトでsingle()
メソッドを呼び出しています。upload
オブジェクトでは、さまざまなデータ構成に適した多くのメソッドを呼び出すことができます。この例では、ファイルを1つのみアップロードしているため、single()
メソッドを使用します。
この時点で、エンドポイントのコールバック関数で使用可能な req
オブジェクトは、一般的なreq
とは少し異なります。POST
リクエストを実行したときに、フォームにbody
の値を添付していないにもかかわらず、非ファイルフォームのフィールドの値はreq.body
で使用可能になります。
アップロードしたファイルはreq.file
で使用可能になります。前述のコードでは、これらのオブジェクトの両方がコンソールに記録されます。以下では、これらの表示を確認するために、プロジェクトをテストします。
アプリケーションをテストする
ターミナルで、express_app
ディレクトリ内にいることを確認してから、次のコマンドを実行します。
ローカルサーバーがPORT 3000
で起動します。
新しいターミナルウィンドウを開き、Node.jsプロジェクトに戻ります。
次のコマンドでスクリプトを実行します。
POST
リクエストが成功すると、ターミナルに「Upload complete」のメッセージが表示され、失敗するとエラーメッセージが表示されます。
Expressアプリケーションを実行しているターミナルでもう一度確認します。ファイルのタイトルおよびファイルを表すオブジェクトとファイルのタイトルが表示されます。ファイルをディスクに保存すると、path
キーがあることが分かります。このパスを使用すると、(ファイルをGoogleドライブにアップロードするために必要だったように)別の読み取り可能なストリームを作成できます。
この記事では、Node.jsアプリケーションからExpressにファイルを直接アップロードする方法について学びました。ご質問がある場合は、Twitterでお問い合わせください。
Ashleyは、TwilioブログのJavaScriptエディターです。Ashleyと協力し、Twilioにテクニカルストーリーを紹介するには、Twitter[@ahl389](https://twitter.com/ahl389)経由でご連絡ください。TwitterでAshleyが見つからない場合は、どこかのパティオでコーヒーを飲んでいることでしょう(ワインの時間かも)。