NotionRubyMapping のアップデート(8) : hkob の雑記録 (163)

はじめに

hkob の雑記録の第163回目は、multipart のテストがうまく行えなかったことを記載します。

FileUploadObject#single_file_upload

とりあえず single_file_upload を実装してみました。作成した FileUploadObject の @id とファイル名を file_upload_request に投げているだけです。

  def single_file_upload
    nc = NotionRubyMapping::NotionCache.instance
    response = nc.file_upload_request @fname, @id
    return if response[:id] == @id && response[:status] == "uploaded"

    raise StandardError,
          "File upload failed: #{response}"
  end

Notioncache#file_upload_request

file_upload_request は file_upload_path で作成した path に Multipart の request を送るだけです。

    # @param [String] fname
    # @param [String] id
    # @param [Hash] options
    # @return [Hash]
    def file_upload_request(fname, id, options = {})
      multipart_request(file_upload_path(id), options, fname)
    end

file_upload_path のテスト

file_uploads_path のテストは簡単です。

    describe "file_upload_path" do
      it { expect(nc.file_upload_path("ABC")).to eq "v1/file_uploads/ABC/send" }
    end

NotionCache#file_upload_path

実装は簡単ですね。

    # @param [String] id
    # @return [String]
    def file_upload_path(id)
      "v1/file_uploads/#{id}/send"
    end

NotionCache#multipart_request

multipart_request は Faraday::Multipart を使った専用の request です。

    # @param [String] path
    # @param [Hash] json
    # @param [String] fname
    # @return [Hash] response hash
    def multipart_request(path, json, fname)
      raise "Please call `NotionRubyMapping.configure' before using other methods" unless @notion_token

      sleep @wait
      json_part = Faraday::Multipart::ParamPart.new(json.to_json, "application/json")
      file_part = Faraday::Multipart::FilePart.new(fname, "application/octet-stream", File.basename(fname))
      response = multipart_client.send(:post) do |request|
        request.headers["Authorization"] = "Bearer #{@notion_token}"
        request.headers["content-Type"] = "multipart/form-data"
        request.path = path
        request.body = {json: json_part, file: file_part}
      end
      p response.body if @debug
      response.body
    end

NotionCache#multipart_client

multipart_client は毎回使うわけではないので、オプショナルのインスタンス変数にしました。conn.request に :multipart が設定されている点が通常の @client と異なる点です。

    def multipart_client
      @multipart_client ||= Faraday.new "https://api.notion.com" do |conn|
        conn.request :multipart
        conn.response :json, parser_options: {symbolize_names: true}
        conn.headers["Notion-Version"] = NotionRubyMapping::NOTION_VERSION
      end
    end

WebMock の設定

FileUploadObject のテストを色々と頑張ったのですが、body のチェックで文字列比較をするときに UTF-8 と ASCII-8BIT の混ざったものを取り扱った瞬間にエラーになってしまうようです。body の比較をスキップする設定などを色々と試しているのですが、今のところうまくいっていません。テストで時間をかけても仕方がないので、簡易実装で動作することを確認したら、アップロード部分だけ WebMock ではなく、メソッドの stub で逃げてしまうかもしれません。

  1) FileUploadObject initialize with a small file creates a new FileUploadObject
     Failure/Error:
       response = multipart_client.send(:post) do |request|
         request.headers["Authorization"] = "Bearer #{@notion_token}"
         request.headers["content-Type"] = "multipart/form-data"
         request.path = path
         request.body = {json: json_part, file: file_part}
       end
     
     Encoding::CompatibilityError:
       incompatible character encodings: BINARY (ASCII-8BIT) and UTF-8

おわりに

今日は忙しくて全くコードに触れることができず、進捗がありませんでした。

hkob.notion.site