Retrofit2: Modifying request body in OkHttp Interceptor
Since this cannot be written in the comments of the previous answer by @Fabian, I am posting this one as separate answer. This answer deals with both "application/json" as well as form data.
import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
/**
* Created by debanjan on 16/4/17.
*/
public class TokenInterceptor implements Interceptor {
private Context context; //This is here because I needed it for some other cause
//private static final String TOKEN_IDENTIFIER = "token_id";
public TokenInterceptor(Context context) {
this.context = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody requestBody = request.body();
String token = "toku";//whatever or however you get it.
String subtype = requestBody.contentType().subtype();
if(subtype.contains("json")){
requestBody = processApplicationJsonRequestBody(requestBody, token);
}
else if(subtype.contains("form")){
requestBody = processFormDataRequestBody(requestBody, token);
}
if(requestBody != null) {
Request.Builder requestBuilder = request.newBuilder();
request = requestBuilder
.post(requestBody)
.build();
}
return chain.proceed(request);
}
private String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
private RequestBody processApplicationJsonRequestBody(RequestBody requestBody,String token){
String customReq = bodyToString(requestBody);
try {
JSONObject obj = new JSONObject(customReq);
obj.put("token", token);
return RequestBody.create(requestBody.contentType(), obj.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private RequestBody processFormDataRequestBody(RequestBody requestBody, String token){
RequestBody formBody = new FormBody.Builder()
.add("token", token)
.build();
String postBodyString = bodyToString(requestBody);
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
return RequestBody.create(requestBody.contentType(), postBodyString);
}
}
I using this to add post parameter to the existing ones.
OkHttpClient client = new OkHttpClient.Builder()
.protocols(protocols)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
RequestBody formBody = new FormEncodingBuilder()
.add("email", "[email protected]")
.add("tel", "90301171XX")
.build();
String postBodyString = Utils.bodyToString(request.body());
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + Utils.bodyToString(formBody);
request = requestBuilder
.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString))
.build();
return chain.proceed(request);
}
})
.build();
public static String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
OkHttp3:
RequestBody formBody = new FormBody.Builder()
.add("email", "[email protected]")
.add("tel", "90301171XX")
.build();
I'll share my Kotlin implementation of @Fabian's answer using Dagger. I wanted origin=app
added to the request url for GET requests, and added to the body for form-encoded POST requests
@Provides
@Singleton
fun providesRequestInterceptor() =
Interceptor {
val request = it.request()
it.proceed(when (request.method()) {
"GET" -> {
val url = request.url()
request.newBuilder()
.url(url.newBuilder()
.addQueryParameter("origin", "app")
.build())
.build()
}
"POST" -> {
val body = request.body()
request.newBuilder()
.post(RequestBody.create(body?.contentType(),
body.bodyToString() + "&origin=app"))
.build()
}
else -> request
})
}
fun RequestBody?.bodyToString(): String {
if (this == null) return ""
val buffer = okio.Buffer()
writeTo(buffer)
return buffer.readUtf8()
}
You can edit the request body by below method, Pass the request and the parameter to edit.
private fun editBody(request: Request, parameter: String): RequestBody {
val oldBody = request.body //retrieve the current request body
val buffer = Buffer()
oldBody?.writeTo(buffer)
val strOldBody = buffer.readUtf8() // String representation of the current request body
buffer.clear()
buffer.close()
val strNewBody = JSONObject(strOldBody).put("parameter", parameter).toString()
return strNewBody.toRequestBody(request.body?.contentType()) // New request body with the encrypted/modified string of the current request body
}
Now you can request again with updated request body
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
return chain.proceed(requestWithUpdatedParameter(request, "parameter"))
}
private fun requestWithUpdatedParameter(req: Request, parameter: String): Request {
val newRequest: Request
val body = editBody(req, parameter)
newRequest = req.newBuilder().method(req.method, body).build()
return newRequest
}