Using local JSON files as an API placeholder with Retrofit

With this snippet you can easily and quickly mock an API during developmentby placing JSON files in your res/raw/ folder. This comes in handy when the actual API does not exist yet.

For mocking an API for unit tests, have a look at Retrofit’s MockService (GitHub).


When creating your Retrofit instance, you can add a MockIntercepter which transforms each request into reading from res/raw/ instead:

val mockInterceptor = MockInterceptor()
mockClient = OkHttpClient.Builder()

In your Retrofit instance, use this client instead of the regular client. For example:

private val retrofit = Retrofit.Builder()
        .client(if (BuildConfig.DEBUG) mockClient else okHttpClient)

Mock Interceptor

The Mock Interceptor transforms the requests to load the response from a file:

class MockInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val url = chain.request().url()
        val path = "res/raw/${url.getLastPathSegment()}"
        val response = path.readFile(this)

        require(!response.isNullOrEmpty()) { "JSON file $path should exist and not be empty" }

        return Response.Builder()
            .body(ResponseBody.create(MediaType.parse("application/json"), response))
            .addHeader("content-type", "application/json")

This assumes the following extension functions:

 * Opens an InputStream to the specified path.
 * Pro tip: By prefixing `raw/` or `res/raw/` to the String you can load files from res/raw without a Context.
fun String.openStream(clz: Any) = clz.javaClass.classLoader?.getResourceAsStream(this)

fun InputStream.readFile() = this.bufferedReader().use(BufferedReader::readText)

fun String.readFile(clz: Any) = this.openStream(clz)?.readFile()

 * Added a convenient shortcut here because Android's Uri class
 * has a getLastPathSegment method but OkHttp does not.
fun HttpUrl.getLastPathSegment(): String = this.pathSegments().last()

Api Service

Now, if your ApiService looks like this:

interface ApiService {
    suspend fun getExample(): ExampleResponse

The file will be loaded from res/raw/example.json instead.