87

So, back when I was using Koush's Ion, I was able to add a json body to my posts with a simple .setJsonObjectBody(json).asJsonObject()

I'm moving over to OkHttp, and I really don't see a good way to do that. I'm getting error 400's all over the place.

Anyone have any ideas?

I've even tried manually formatting it as a json string.

String reason = menuItem.getTitle().toString();
JsonObject json = new JsonObject();
json.addProperty("Reason", reason);

String url = mBaseUrl + "/" + id + "/report";

Request request = new Request.Builder()
        .header("X-Client-Type", "Android")
        .url(url)
        .post(RequestBody
                .create(MediaType
                    .parse("application/json"),
                        "{\"Reason\": \"" + reason + "\"}"
                ))
        .build();

client.newCall(request).enqueue(new com.squareup.okhttp.Callback() {
    @Override
    public void onFailure(Request request, IOException throwable) {
        throwable.printStackTrace();
    }

    @Override
    public void onResponse(Response response) throws IOException {
        if (!response.isSuccessful()) throw new IOException(
                "Unexpected code " + response);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "Report Received", Toast.LENGTH_SHORT).show();
            }
        });
    }
});

/*Ion.with(getContext(), url)
        .setHeader("X-Client-Type", "Android")
        .setJsonObjectBody(json)
        .asJsonObject()
        .setCallback(new FutureCallback<JsonObject>() {
            @Override
            public void onCompleted(Exception e, JsonObject result) {
                Toast.makeText(context, "Report Received", Toast.LENGTH_SHORT).show();
            }
        });*/
Pixel Perfect
  • 1,266
  • 1
  • 11
  • 14

4 Answers4

169

Just use JSONObject.toString(); method. And have a look at OkHttp's tutorial:

public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(json, JSON); // new
  // RequestBody body = RequestBody.create(JSON, json); // old
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}
zvyap
  • 3
  • 3
Ostap Andrusiv
  • 4,827
  • 1
  • 35
  • 38
  • Well, I need to see if the backend is even working properly. Your code acts identically to mine - crashing when I supply one thing for the string in the JSON, but working when I supply something different. – Pixel Perfect Dec 09 '15 at 13:59
  • Turns out, my issue was just that my JSON data itself was wrong. I was supplying an incorrect string. "Copyright".equals("CopyrightInfringement") returns false – Pixel Perfect Dec 10 '15 at 12:57
  • Do you have any way of going about it when the string is more than 32K characters without it being truncated? I've been facing this problem lately. – Clement Osei Tano Jul 14 '19 at 08:36
  • 5
    RequestBody.create() is **Deprecated** – Iman Marashi Oct 02 '19 at 12:47
  • 7
    @Iman Marashi It's not the method name which is deprecated. It's the method argument which is deprecated. Actually, the latest version only replacing the MediaType as 2nd argument. Nothing more is changed. So, it should be ```RequestBody body = RequestBody.create(json, JSON);``` And..... problem solved – poring91 Jan 24 '20 at 11:12
  • @Ostap Andrusiv Any other way ? Because this method is deprecated. – Hardik Parmar Feb 04 '20 at 11:33
  • 2
    @HardikParmar, it's not the method name that was deprecated, but an argument. Just replace the first and the second arguments, as poring91 mentioned – Ostap Andrusiv Feb 06 '20 at 16:28
  • In http4 is a bit different, see https://stackoverflow.com/a/60110536/833499 – lcapra Feb 07 '20 at 09:26
  • `Cannot resolve method create(String, MediaType)` error – parsecer Sep 23 '20 at 15:09
  • 1
    This is an outdated solution. Please see answer from @Allen. – Firzen Jul 06 '21 at 15:15
30

You can create your own JSONObject then toString().

Remember run it in the background thread like doInBackground in AsyncTask.

OkHttp version > 4:

import okhttp3.MediaType.Companion.toMediaType

// create your json here
JSONObject jsonObject = new JSONObject();
try {
    jsonObject.put("KEY1", "VALUE1");
    jsonObject.put("KEY2", "VALUE2");
} catch (JSONException e) {
    e.printStackTrace();
}

val client = OkHttpClient()
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = jsonObject.toString().toRequestBody(mediaType)
val request: Request = Request.Builder()
            .url("https://YOUR_URL/")
            .post(body)
            .build()

var response: Response? = null
try {
    response = client.newCall(request).execute()
    val resStr = response.body!!.string()
} catch (e: IOException) {
    e.printStackTrace()
}
   

OkHttp version 3:

// create your json here
JSONObject jsonObject = new JSONObject();
try {
    jsonObject.put("KEY1", "VALUE1");
    jsonObject.put("KEY2", "VALUE2");
} catch (JSONException e) {
    e.printStackTrace();
}

  OkHttpClient client = new OkHttpClient();
  MediaType JSON = MediaType.parse("application/json; charset=utf-8");
  // put your json here
  RequestBody body = RequestBody.create(JSON, jsonObject.toString());
  Request request = new Request.Builder()
                    .url("https://YOUR_URL/")
                    .post(body)
                    .build();

  Response response = null;
  try {
      response = client.newCall(request).execute();
      String resStr = response.body().string();
  } catch (IOException e) {
      e.printStackTrace();
  }
Allen
  • 2,979
  • 1
  • 29
  • 34
  • 2
    This does not work: `val mediaType = "application/json; charset=utf-8".toMediaType();`. – LuGeNat Dec 11 '21 at 12:58
  • if i try this ---> RequestBody body = RequestBody.create(JSON, jsonObject.toString()); added JSON Array inside JSON object, array value become string, want to pass only JSON Array data not string, anyone help me to solve this – Kumararaja Feb 28 '22 at 02:19
11

Another approach is by using FormBody.Builder().
Here's an example of callback:

Callback loginCallback = new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        try {
            Log.i(TAG, "login failed: " + call.execute().code());
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // String loginResponseString = response.body().string();
        try {
            JSONObject responseObj = new JSONObject(response.body().string());
            Log.i(TAG, "responseObj: " + responseObj);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        // Log.i(TAG, "loginResponseString: " + loginResponseString);
    }
};

Then, we create our own body:

RequestBody formBody = new FormBody.Builder()
        .add("username", userName)
        .add("password", password)
        .add("customCredential", "")
        .add("isPersistent", "true")
        .add("setCookie", "true")
        .build();

OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(this)
        .build();
Request request = new Request.Builder()
        .url(loginUrl)
        .post(formBody)
        .build();

Finally, we call the server:

client.newCall(request).enqueue(loginCallback);
Blo
  • 11,903
  • 5
  • 45
  • 99
  • Thanks, this answer work for me very well. But I have a question, what would be the best approach to sending an extra parameter with JSON type. This is how the request works [image](http://i.imgur.com/MdScLhK.png), and this is how I sending the `RequestBody` information [image](http://i.imgur.com/9RqoKMQ.png). The code works well but I receive an error from the response telling me that the Image parameter was incorrect. Maybe I need to turn into an object and parse to `String`?. Thanks in advance –  May 16 '17 at 19:25
  • 2
    How do you add JSON to a FormBody as a block without having to add each key value pair by hand. – user3561494 Aug 03 '20 at 18:03
7

In kotlin, in okhttp v4.* I got it working that way


// import the extensions!
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

// ...

json : String = "..."

val JSON : MediaType = "application/json; charset=utf-8".toMediaType()
val jsonBody: RequestBody = json.toRequestBody(JSON)

// go on with Request.Builder() etc

lcapra
  • 1,420
  • 16
  • 18