TransWikia.com

Read plain text response from server using Retrofit

Stack Overflow Asked by Renjith on December 22, 2021

I’m working on an application that uses Retrofit for network operations. As it stands, everything works well with GsonConverterFactory handling serialization. Here is how I setup Retrofit

Retrofit.Builder()
        .baseUrl("<base url>") 
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()

Now I need to connect to a legacy service which returns content in text/plain; charset=utf-8 format. Here is the Retrofit interface

@GET("https://<domain>/<endpoint>?Type=Query")
suspend fun callStatus(@Query("userId") id: Int): Response<String>

This will return status of a call for a valid user. For instance, if the user is valid and there is a status, it returns "Active" as plain text. If there is no valid user, it returns an error code of #1005

I could add custom converter factory like this (found on the web)

final class StringConverterFactory implements Converter.Factory {
    private StringConverterFactory() {}

    public static StringConverterFactory create() {
        return new StringConverterFactory();
    }

    @Override
    public Converter<String> get(Type type) {
        Class<?> cls = (Class<?>) type;
        if (String.class.isAssignableFrom(cls)) {
            return new StringConverter();
        }
        return null;
    }

    private static class StringConverter implements Converter<String> {
        private static final MediaType PLAIN_TEXT = MediaType.parse("text/plain; charset=UTF-8");

        @Override
        public String fromBody(ResponseBody body) throws IOException {
            return new String(body.bytes());
        }

        @Override
        public RequestBody toBody(String value) {
            return RequestBody.create(PLAIN_TEXT, convertToBytes(value));
        }

        private static byte[] convertToBytes(String string) {
            try {
                return string.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

But I didn’t see it make any difference. Also, it could well disguise JSON as normal text and break all existing service. Is there a better way to handle this scenario? I thought of having separate retrofit instance for plain text, bit dirty though. Do you have any other suggestions/solutions?

Edited

Response header contains the content type as
Content-Type: text/plain; charset=utf-8

Actual response for valid user

Active

Actual response for invalid user

#1005

4 Answers

Two things to check first that function should not be suspended & your response should be in the Callback

No need to add extra implementation of scalars.

@GET
    fun getJson(
        @Url baseUrl: String = slab_pro
    ): Call<DataClass>

Answered by Adam Noor on December 22, 2021

The following is the way that how I get response as plain text (using Java not Kotlin).

Step One

in your gradle (Module);

    implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'

Step Two

Create an interface

public interface MyInterface {
    @GET("something.php")
    Call<String> getData(@Query("id") String id,
                         @Query("name") String name);
}

Step Three

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://example.com")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

MyInterface myInterface = retrofit.create(MyInterface.class);
Call<String> call = myInterface.getData("id","myname");
call.enqueue(new Callback<String>() {
                    @Override
                    public void onResponse(Call<String> call, Response<String> response) {
                        String plain_text_response = response.body();
                    }

                    @Override
                    public void onFailure(Call<String> call, Throwable t) {

                    }
                });

Answered by ZBorkala on December 22, 2021

Update


The order in which you register the converter factories matters. ScalarsConverterFactory must come first.


it should be possible by adding ScalarsConverterFactory when building the Retrofit object.
This can be done alongside with other json converters, e.g.

Retrofit.Builder()
        .baseUrl("<base url>") 
        .client(client)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()

After that, you should be able to receive plaintext responses.

You probably need to add this to your dependencies as well:

implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'

Answered by Adrian K on December 22, 2021

You don't need to use a your custom implementation of Converter.Factory you could just use

// your coroutine context
    val response = callStatus(userId)
    if(response.isSuccessful){
        val plainTextContent = response.body()
        // handle plainText
    } else {
     //TODO: Handle error
    }
 //...

Answered by Arpan Sarkar on December 22, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP