multipart/form-dataを使ってAzure Functions(TypeScript)にデータを転送する

C#でのサンプルは簡単に見つかったけど、TypeScriptの場合どうすればいいのか?ということで調査しました。

以下の内容がドンピシャなんですが、req.parseFormBody()を使えばいけるようです。

https://github.com/Azure/azure-functions-nodejs-worker/issues/347

注意点としては、このメソッドが使用できるのはNode.js workerのv3.2.0以降という部分です。ちょっとわかりにくいですが、Azure Functions v4 は v3 の Node.js worker を使っていて、v3 は v2 を使っています。

ソース

HttpTriggerで使います。
index.tsの内容

import { AzureFunction, Context, HttpRequest} from "@azure/functions";
import { BlobServiceClient } from "@azure/storage-blob";

const httpTrigger: AzureFunction = async function (
  context: Context,
  req: HttpRequest
): Promise<void> {
    const fBody = req.parseFormBody()
    const excel = fBody.get("excel")
    console.log(excel)
  
  const STORAGE_CONNECTION_STRING = process.env.STORAGE_CONNECTION_STRING || "";
  const blobServiceClient = BlobServiceClient.fromConnectionString(
    STORAGE_CONNECTION_STRING
  );

  // Blobのコンテナーがなければ作成する
  const containerName = 'excel-container';
  const containerClient = blobServiceClient.getContainerClient(containerName);
  const hasContainer = await containerClient.exists()
  if (!hasContainer) {
    const createContainerResponse = await containerClient.create();
    console.log(
      `Create container ${containerName} successfully`,
      createContainerResponse.requestId
    );
  }
  const excelName = excel.fileName ?? ""
  const blobClient = containerClient.getBlockBlobClient(excelName)
  const hasItem = await blobClient.exists
  if (!hasItem) {
 // Excel保存
    const uploadBlobResponse = await blobClient.upload(excel.value, Buffer.byteLength(excel.value));
    console.log(`Upload block blob ${excelName} successfully`, uploadBlobResponse.requestId);
  }
};

export default httpTrigger;

ざっくり解説

req.parseFormBodyについて

HttpRequestに、”x-www-form-urlencoded” および “multipart/form-data” タイプのコンテンツを解析するために使用できるメソッドです。Azure Functions v4 で使えます。

こんな感じ。

export interface HttpRequest {
    // ...

    parseFormBody(): Promise<Form>;
}

export interface Form extends Iterable<[string, FormPart]> {
    /**
     * Returns the value of the first name-value pair whose name is `name`. If there are no such pairs, `null` is returned.
     */
    get(name: string): FormPart | null;

    /**
     * Returns the values of all name-value pairs whose name is `name`. If there are no such pairs, an empty array is returned.
     */
    getAll(name: string): FormPart[];

    /**
     * Returns `true` if there is at least one name-value pair whose name is `name`.
     */
    has(name: string): boolean;
}

export interface FormPart {
    value: Buffer;
    fileName?: string;
    contentType?: string;
}

なので、実際に使う時は以下みたいにします。

    const fBody = req.parseFormBody()
    const excel = fBody.get("excel")

HTTPリクエストは以下のようにしてます。

動作確認のためにBlobにExcel保存してダウンロードして確認

excel-containerというコンテナーを作って
その中にExcelファイルを保存しています。
当該部分をソースコードのコメントに書いてます。

Microsoft Azure Storage Explorerでデータダウンロードして確認します。