質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

2回答

3964閲覧

[Android-kotlin]APIを叩いて文字列とファイルをPOSTしたい

退会済みユーザー

退会済みユーザー

総合スコア0

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2021/10/28 06:32

編集2021/10/28 08:21

###やりたいこと

お世話になります。Androidアプリ内でファイルを解析してくれるWEBサービスを利用したいです。

それにはapikeyと解析対象のファイルをサービスへPOSTする必要がありますので、その処理を実装したのですが、「apikeyの値がnullか空」という旨のエラーコードを返されてしまいます。これを解決したいです。

###APIの仕様書
こちらになります。今回はAPI version V2を利用するものとします。
イメージ説明

###コードと問題点
retrofit2とOKhttpを使用しています。
まずはInterfaceから

Kotlin

1#Myservice.kt 2 3import okhttp3.RequestBody 4import okhttp3.ResponseBody 5import retrofit2.Call 6import retrofit2.http.* 7import okhttp3.MultipartBody 8import retrofit2.Response 9import retrofit2.http.POST 10 11interface MyService{ 12 @Multipart 13 @POST("v2/analyzeWav") 14 fun postRawRequestForPosts( 15 @Part file: MultipartBody.Part, 16 @Part("testpart") requestBody : RequestBody 17 ):Call<ResponseBody> 18}

こちらはMainactivity.ktです。

Kotlin

1#MainActivity.kt 2 3package jp.co.casareal.retrofitbasic 4 5import android.os.Bundle 6import android.util.Log 7import android.view.View 8import android.widget.Toast 9import androidx.appcompat.app.AppCompatActivity 10import androidx.databinding.DataBindingUtil 11import androidx.lifecycle.ViewModelProvider 12import jp.co.casareal.retrofitbasic.databinding.ActivityMainBinding 13import jp.co.casareal.retrofitbasic.util.Util 14import kotlinx.coroutines.CoroutineScope 15import kotlinx.coroutines.Dispatchers 16import kotlinx.coroutines.launch 17import okhttp3.MediaType 18import okhttp3.MultipartBody 19import okhttp3.RequestBody 20import retrofit2.Retrofit 21import java.io.File 22 23class MainActivity : AppCompatActivity() { 24 25 // Retrofit本体 26 private val retrofit = Retrofit.Builder().apply { 27 baseUrl(" https://api.webempath.net/") 28 }.build() 29 30 // サービスクラスの実装オブジェクト取得 31 private val service = retrofit.create(MyService::class.java) 32 33 private val myViewModel: MyViewModel by lazy { 34 ViewModelProvider.NewInstanceFactory().create(MyViewModel::class.java) 35 } 36 37 private val scope = CoroutineScope(Dispatchers.IO) 38 39 override fun onCreate(savedInstanceState: Bundle?) { 40 super.onCreate(savedInstanceState) 41 val binding = 42 DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) 43 44 binding.model = myViewModel 45 binding.lifecycleOwner = this 46 } 47 48 /** POSTボタンが押された時の処理*/ 49 fun onPostButtonClick(view: View) { 50 51 if (!myViewModel.author.value.isNullOrBlank() && !myViewModel.title.value.isNullOrBlank()) { 52 53 //apikey送信設定 54 val strContent = "{ 'apikey' : '自分のAPIキー'}" 55 val mediaTypebody = MediaType.parse("application/json") 56 val reqBodybody = RequestBody.create(mediaTypebody, strContent) 57 58 //wavファイル送信設定 59 val filepath = "解析対象のファイルのパス" 60 val audioFile = File(filepath) 61 val mediaTypefile = MediaType.parse("audio/*") 62 val reqBodyfile = RequestBody.create(mediaTypefile, audioFile) 63 val part = MultipartBody.Part.createFormData("part_name", audioFile.name, reqBodyfile) 64 65 val post = service.postRawRequestForPosts(part,reqBodybody) 66 67 scope.launch { 68 val responseBody = post.execute() 69 responseBody.body()?.let { 70 myViewModel.result.postValue(it.string()) 71 } 72 } 73 } 74 } 75 76

※画面上にresponseを表示するという処理をさせているだけなのでレイアウトとviewmodelは省略します。

このコードを実行すると、{"error":1001,"msg":"apikey is null or empty"}と返されます。
curlで同じapikeyを送信すると1001エラーが出てこなかったためapikey自身には問題がなさそうで、
エラーコードからAPI仕様書を見ても同じような旨なのでapikeyがうまく送信されていないと思っています。

###知りたいこと、わからないこと
apikeyはMediaType.parse("application/json")でPOSTしていますが、こちらがいけないのでしょうか?

下記に並べている参考文献を含めPOSTで文字列を送る際はjsonで送るケースばかりで特別問題があるように思えませんが、エラー的にapikeyの送信に問題がありそうなので怪しいのかなと思っています。

よろしくおねがいします。

###追記
そもそもjson形式で送ってはいけないのでは?という指摘を頂いたので念の為仕様書にあったサンプルコードを追記します。(同時並行でmultipartでの文字列の取り扱いについても調べてまいりますイメージ説明

###参考にした文献
Let's はじめてのRetrofit for Android in Kotlin(サンプルコード付き)

retrofit multipart送信を行う

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

たぶんこれでいける、かも?

Myservice.kt

  • requestBody のパート名は apikey にする

diff

1 fun postRawRequestForPosts( 2 @Part file: MultipartBody.Part, 3- @Part("testpart") requestBody : RequestBody 4+ @Part("apikey") requestBody: RequestBody 5 ):Call<ResponseBody>

MainActivity.kt

  • reqBodybody の中身は API キーそのまま、mime type は plain text
  • part のパート名は wav にして、mime type も wav にする

diff

1 //apikey送信設定 2- val strContent = "{ 'apikey' : '自分のAPIキー'}" 3- val mediaTypebody = MediaType.parse("application/json") 4+ val strContent = "自分のAPIキー" 5+ val mediaTypebody = MediaType.parse("text/plain") 6 val reqBodybody = RequestBody.create(mediaTypebody, strContent) 7 8 //wavファイル送信設定 9 val filepath = "解析対象のファイルのパス" 10 val audioFile = File(filepath) 11- val mediaTypefile = MediaType.parse("audio/*") 12+ val mediaTypefile = MediaType.parse("audio/wav") 13 val reqBodyfile = RequestBody.create(mediaTypefile, audioFile) 14- val part = MultipartBody.Part.createFormData("part_name", audioFile.name, reqBodyfile) 15+ val part = MultipartBody.Part.createFormData("wav", audioFile.name, reqBodyfile) 16 17 val post = service.postRawRequestForPosts(part, reqBodybody)

投稿2021/10/28 08:35

hoshi-takanori

総合スコア7895

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/10/28 08:46

うまくいきました...!ありがとうございます...! 今回うまく行かなかったのはKAOsaka様がおっしゃっていたようにmutlipartなのでそもそもjsonで送ってはNGだったこと、interfaceの@PARTのstring部とMultipartBody.Part.createFormDataの第一引数が項目として送られるからそこを直してうまくいった、という認識であってますか?
hoshi-takanori

2021/10/28 08:59

実は webempath のサイトに node.js のコードがあったので、同じ形式で送られるようにしてみました。今回の場合、multipart の各パートの名前を合わせることと、api キーをそのまま送ることがポイントだと思います。
退会済みユーザー

退会済みユーザー

2021/10/28 09:17

原因や試したことも記述してくださりありがとうございました。目的が果たされたのでBAといたします。
guest

0

こちらのキーと値を囲っているシングルクオートをダブルクオートにしてもダメでしょうか?

kotlin

1val strContent = "{ 'apikey' : '自分のAPIキー'}"

追記

Unexpected token (use ' ; ' to separate expressions on the same line
エラーが出ると同時にapikeyと中身両方共 Unresolved refference出ちゃいます...

多分こうしちゃってると思いますので

kotlin

1val strContent = "{ "apikey" : "自分のAPIキー"}"

こうしてください。

kotlin

1val strContent = "{ \"apikey\" : \"自分のAPIキー\" }"

投稿2021/10/28 07:04

編集2021/10/28 07:19
KAOsaka

総合スコア531

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/10/28 07:12

Unexpected token (use ' ; ' to separate expressions on the same line エラーが出ると同時にapikeyと中身両方共 Unresolved refference出ちゃいます...
KAOsaka

2021/10/28 07:19

回答追記しましたのでご確認ください。
退会済みユーザー

退会済みユーザー

2021/10/28 07:24

追記ありがとうございます、書いてあったとおりにやってしまっていたので新しく試してみましたが1001エラーのままでした...
KAOsaka

2021/10/28 07:28

そうですか、、、ちなみにAPI Keyにバックスラッシュとか入ってたりしないですか?
退会済みユーザー

退会済みユーザー

2021/10/28 08:04

apikeyは小文字と大文字のローマ字と数字のみで構成されてます...
KAOsaka

2021/10/28 08:15

今気づいたんですがAPI仕様的にはContent-Type: multipart/form-dataなのでJSON形式でAPIKeyを使用してるのがおかしいのかもしれませんね。
退会済みユーザー

退会済みユーザー

2021/10/28 08:18

なるほど、その場合だと MediaType.parse("application/json") より MediaType.parse("plain/text") のほうが適切という感じなんでしょうか? ちょっと、念の為API仕様書のサンプルコード(curl,java)も追記します
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問