📙

【Dart/Flutter】httpパッケージを使ってMultipart形式のリクエストを送る

2023/02/28に公開

【Dart/Flutter】httpパッケージを使ってMultipart形式のリクエストを送る

概要

DartFlutter でHTTPリクエストを扱う際には既に定番となっている http パッケージですが、残念なことにMultipart形式のリクエストを簡単に送るためのメソッドが用意されていません。

SNSなどで提供されているWeb APIを使用して面白い画像や動画をプログラムからアップロードしたい場合にはほとんどの場合でMultipart形式のHTTPリクエストを送る必要がありますが、http パッケージでは自分でMultipart形式のリクエストを送る実装をしなければいけないので敬遠している方も少なくないのではないかと思います。

しかし、実際のところこれを実装するのはとても簡単で、この記事で紹介する手順を読めば必ず実装できるようになります。私が開発している twitter_api_v2mastodon_api で使用している実装でもあるので、その他の多くのWeb APIに対しても応用が可能です!

https://pub.dev/packages/twitter_api_v2

https://pub.dev/packages/mastodon_api

前提

この記事を読み進めるにあたっての前提事項です。

  • Dart の基本的な文法がわかること。
  • Dart の実行環境が既にあること。
  • http パッケージについて知っている、またはHTTPがなにか知っていること。

httpパッケージのインストール

まずは以下のお馴染みのコマンドで http パッケージをインストールしましょう。

Dart:

dart pub add http

Flutter:

flutter pub add http

また、必要に応じて以下のコマンドを実行しましょう。

Dart:

dart pub get

Flutter:

flutter pub get

実装

結論から始めると以下の実装で http パッケージを使用してMultipart形式のリクエストを送信可能です。

Future<void> main(List<String> args) async {
  final response = await multipart(
    method: 'POST',
    url: Uri.https('xxxx.com', '/v1/api/something'),
    files: [
      http.MultipartFile.fromBytes(
        'media',
        File('./media/xxxx.jpg').readAsBytesSync(),
      ),
    ],
  );

  print(response.statusCode);
  print(response.body);
}

Future<http.Response> multipart({
  required String method,
  required Uri url,
  required List<http.MultipartFile> files,
}) async {
  final request = http.MultipartRequest(method, url);

  request.files.addAll(files); // 送信するファイルのバイナリデータを追加
  request.headers.addAll({'Authorization': 'Bearer xxxxxx'}); // 認証情報などを追加

  final stream = await request.send();

  return http.Response.fromStream(stream).then((response) {
    if (response.statusCode == 200) {
      return response;
    }

    return Future.error(response);
  });
}

HTTPについて詳しい方であれば上記の実装を見ただけでなんとなく理解できると思いますが、少し難しい実装であるため簡単に説明していきます。

Multipartリクエストを生成する

まず、Multipart形式のリクエストを送るためには、その名の通り MultipartRequest オブジェクトを使用します。MultipartRequest オブジェクトのインスタンスを生成する際には HTTPメソッドを表す文字列リクエストを送信する先のURL が必要です。

final request = http.MultipartRequest(method, url);

例えば、上記の例に値を当てはめると以下のようになります。

final request = http.MultipartRequest(
  'POST',
  Uri.https('xxxx.com', '/v1/api/something'),
);

Multipartリクエストにファイルを設定する

Multipartリクエストを生成できたら、リクエストオブジェクトに実際に送信するファイルを設定してみましょう。以下のように設定できます。

final request = http.MultipartRequest(
  'POST',
  Uri.https('xxxx.com', '/v1/api/something'),
);

request.files.addAll(files);

ただ、MultipartRequestfiles フィールドに設定できるファイルのオブジェクトは dart:ioFile ではなく、 http:http.dartMultipartFile であることに注意してください。

例えば、上記の例をより具体的に定義すると以下のようになります。

final request = http.MultipartRequest(
  'POST',
  Uri.https('xxxx.com', '/v1/api/something'),
);

request.files.addAll([
  http.MultipartFile.fromBytes(
    'media',
    File('./media/xxxx.jpg').readAsBytesSync(),
  ),
]);

MultipartFile オブジェクトの作り方はいくつかありますが、dart:ioFile オブジェクトから作るのが楽です。上記の例だとファイルシステムから画像ファイルを取得し、バイトとして読み込んだ上で MultipartFile オブジェクトに渡しています。

また、MultipartFile を生成して、Multipart形式のリクエストを成功させるために重要になるのがフィールド名です。上記の例だと、MultipartFile.fromBytes の第一引数である media がフィールド名になります。

このフィールド名はGET通信時のクエリパラメータにおけるKEYのような役割を持ち、APIサーバーが受け取ったHTTPリクエストを処理する際に重要な名前になります。そのため、このフィールド名は必ず使用するAPIのリファレンスを読んで指定する名前を確認するようにしてください。

Multipartリクエストに認証情報を設定する

Web APIを使用して画像や動画をアップロードするということは、ユーザーの認証が必要になるサービスがほとんどではないかと思います。これはMultipart形式のリクエストに限った話ではないですが、認証情報はリクエストヘッダーに設定することが多いです。

例えば、今では定番となったOAuth 2.0のBearerトークンは以下のように設定できます。

request.headers.addAll({'Authorization': 'Bearer xxxxxx'});

Multipartリクエストを送信する

さて、ここまで来たら後はリクエストを送信するだけです。

final stream = await request.send();

単純に request.send() を実行しただけでは StreamedResponse が返ってくるので、より扱いやすい Response オブジェクトの形式に変換するには以下のようにします。

final stream = await request.send();

return http.Response.fromStream(stream).then((response) {
  if (response.statusCode == 200) {
    return response;
  }

  return Future.error(response);
});

上記の例ではステータスコードが200の場合だけResponseオブジェクトを返却するようにしていますが、こうしなければいけないというわけではなく、必要に応じてカスタマイズしてください。

おまけ: MultipartリクエストにFormデータを設定する

様々なWeb APIのエンドポイントの中にはファイルのバイナリデータと一緒にFormデータを送信できるものがあります。こうしたユースケースであっても MultipartRequest オブジェクトは対応可能です。

以下のようにファイルのバイナリデータと一緒に送信したいFormデータを設定できます。

request.fields.addAll({
  'description': 'This is my funny photo!',
  'alt_text': 'wdyt about it?',
});

最後に

ここまでDartのhttpパッケージを使用してMultipart形式のリクエストを送信する方法を紹介しました。Web APIを使用してプログラムから画像や動画をアップロードする方法がわかったかと思います。

もちろんこの記事で紹介した実装がすべてではありませんので、この記事で紹介した実装を実際に使用するWeb APIに応じてカスタマイズしていただいて構いません。

スポンサーの募集

オープンソース開発をサポートしてくださるスポンサーを募集しています。少額($1)からの寄付も可能ですので、以下のリンクから是非ご支援ください。

https://github.com/sponsors/myconsciousness

また、この記事にバッジを贈っていただくことでも支援は可能です。

GitHubで編集を提案

Discussion