I am trying to send a simple post request to MongoDB using okhttp. Here is the code that I am working with:
try {
String jsonStr = om.writeValueAsString(postRequest);
RequestBody body = RequestBody.create(
jsonStr, MediaType.parse("application/json; charset=utf-8"));
// also attempted with MediaType.parse("application/json")
Request request = new Request.Builder()
.url(insertUrl)
.addHeader("api-key", mongoDbApiKey)
// I have tried following ways to add content-type
// .addHeader("Content-Type", "application/json")
.addHeader("content-type", "application/json")
.post(body)
.build();
String req = request.toString();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new CurlInterceptor(
new Logger() {
@Override
public void log(@NonNull String s) {
Log.v("OK2Curl", s);
// I copied this curl request to postman and it works from postman but for some reason does not work when run from my Android App.
}
}
));
OkHttpClient client = builder.build();
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "Unable to save the data.",
Toast.LENGTH_SHORT).show();
}
@Override public void onResponse(Call call, Response response) throws IOException {
String respString = response.body().string();
// respString => "Header missing: please add content-type: application/json or application/ejson to specify payload data types"
if(response.isSuccessful()){
Toast.makeText(getActivity(), "Data is saved.",
Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getActivity(), "Unable to save the data.",
Toast.LENGTH_SHORT).show();
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
However, when the code is run in my Android App it fails with the following error:
Header missing: please add content-type: application/json or application/ejson to specify payload data types
The HTTP response error code is 400.
Clearly, I have added a header of content-type using multiple ways and the log outputs a curl request that works in postman. What am I missing here? Does the header get removed somewhere by okhttp or something else?
Version:
okhttp3 version 4.10.0
UPDATE 1
I know that there are three methods to add headers in okhttp. addHeader, header and using headers builder. There is not much difference except the headers and header method override the header that is added when MediaType.parse("application/json") is passed to the request on creation. I still get 400 response regardless of the way I add the header to the request.
UPDATE 2
To test my network and parameters such as api-key I have used postman and also Java 11 HttpClient and both methods work.
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(data))
.uri(URI.create(MONGO_DB_URL))
.setHeader("api-key", API_KEY)
.setHeader("Content-Type", "application/json")
.build();
so this problem seems to be specific to okhttp
client.
UPDATE 3
I tried the same scenario using Google’s Volley HTTP library and it worked with that. So for now I can make progress on my app without okhttp.
2
Answers
Create the request body like this:
It seems that okhttp creates its own header based on the body (see also this question) and MongoDB doesn’t like the charset specifier it adds.
I had this same issue with OkHttp3 and Apache HttpClient. user20840950 is correct. This fixes the issue at least for OkHttp3. I did not test this on Apache but I suspect it will work there too because it was producing the exact same behavior. Be sure to add the content type header. The response code should be 201 indicating the data was successfully inserted.
My Request.Builder looks like this: