Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Retrofit LocalJsonClient
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import retrofit.client.Client;
import retrofit.client.Header;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.mime.TypedInput;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
@SuppressLint("DefaultLocale")
public class LocalJsonClient implements Client {
private Context context;
private String scenario = null;
public LocalJsonClient(Context ctx) {
this.context = ctx;
}
public void setScenario(String scenario) {
this.scenario = scenario;
}
@Override
public Response execute(Request request) throws IOException {
URL requestedUrl = new URL(request.getUrl());
String requestedMethod = request.getMethod();
String prefix = "";
if (this.scenario != null) {
prefix = scenario + "_";
}
String fileName = (prefix + requestedMethod + requestedUrl.getPath()).replace("/", "_");
fileName = fileName.toLowerCase();
int resourceId = context.getResources().getIdentifier(fileName, "raw",
context.getPackageName());
if (resourceId == 0) {
Log.wtf("YourTag", "Could not find res/raw/" + fileName + ".json");
throw new IOException("Could not find res/raw/" + fileName + ".json");
}
InputStream inputStream = context.getResources().openRawResource(resourceId);
String mimeType = URLConnection.guessContentTypeFromStream(inputStream);
if (mimeType == null) {
mimeType = "application/json";
}
TypedInput body = new TypedInputStream(mimeType, inputStream.available(), inputStream);
return new Response(request.getUrl(), 200, "Content from res/raw/" + fileName, new ArrayList<Header>(), body);
}
private static class TypedInputStream implements TypedInput {
private final String mimeType;
private final long length;
private final InputStream stream;
private TypedInputStream(String mimeType, long length, InputStream stream) {
this.mimeType = mimeType;
this.length = length;
this.stream = stream;
}
@Override
public String mimeType() {
return mimeType;
}
@Override
public long length() {
return length;
}
@Override
public InputStream in() throws IOException {
return stream;
}
}
}

A Retrofit Client that reads JSON files from disk and returns them as the response (to be handled by GSON). Make sure the context you pass is from the instrumentation app and put your JSON files in res/raw in the instrumentation project. Inspired by Ruby's vcr gem.

A GET request to /articles will look for the JSON file res/raw/get_articles.json, a POST request to /articles/123/ will look for the JSON file res/raw/post_articles_123.json, etc.

We use setScenario() if we want to test alternate responses so that a failed login POST to /login will read from res/raw/failed_login_post_login.json (and the happy path can use post_login.json).

@f2prateek

This comment has been minimized.

Copy link

commented Mar 3, 2014

Other than line 56 and the .json references, this could be extend to any data format (e.g. XML), correct? Retrofit will automatically serialize those appropriate if a custom Converter has been set.

@f2prateek

This comment has been minimized.

Copy link

commented Mar 3, 2014

Also any particular reason you used a raw folder in res instead of assets directly?

@dannyroa

This comment has been minimized.

Copy link

commented Mar 4, 2014

How do we use LocalJsonClient? Where should we substitute it?

@f2prateek

This comment has been minimized.

Copy link

commented Mar 5, 2014

@dannyroa: You can supply it to RestAdapter.Builder with your own Client implementation, such as this one.

@swanson

This comment has been minimized.

Copy link
Owner Author

commented Jun 2, 2014

@f2prateek sorry for the 3 month late reply - yes that is correct about other data formats. I actually use the above code as-is with an XML route in the same app. #guessContentTypeFromStream() does the magic of setting the right mimetype.

No reason on raw vs assets - just where I happened to put them :)

@thalespf

This comment has been minimized.

Copy link

commented Jul 15, 2014

In Retrofit 1.5.1 only work with this Response construct

return new Response(path, 200, "Content from res/raw/" + fileName,
new ArrayList

(), body);

Thanks

@creativepsyco

This comment has been minimized.

Copy link

commented Nov 12, 2014

Since Retrofit 1.6.1

@@ -59,12 +63,14 @@ public class LocalJsonClient implements Client {
         }

         TypedInput body = new TypedInputStream(mimeType, inputStream.available(), inputStream);
-        return new Response(200, "Content from res/raw/" + fileName, new ArrayList<Header>(), body);
+        return new Response(request.getUrl(), 200, "Content from res/raw/" + fileName, new ArrayList<Header>(), body);
@swanson

This comment has been minimized.

Copy link
Owner Author

commented Jan 14, 2015

@creativepsyco - hey thanks. I've updated the code.

@michaeljulio2107

This comment has been minimized.

Copy link

commented Sep 28, 2015

Can you implement this in Retrofit 2.0?

@mbunyard

This comment has been minimized.

Copy link

commented Nov 18, 2016

Below is a link to a gist for an OkHttp3 interceptor, which can be added to an OkHttpClient via OkHttpClient.Builder().addInterceptor() to achieve the response mocking in OkHttp3.

https://gist.github.com/mbunyard/78311b25aaba8b9bfec380f66c868644

@jonneymendoza

This comment has been minimized.

Copy link

commented Jan 16, 2018

Does this work for retrofit 2.0 and how do you use this setup?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.