For the server I'm using, we have a subdomain and a directory both tied together. With Retrofit, you need to specify the baseURL and it doesn't seem to allow directories. Is there a way I can implement this?
Example:
https://dev.myserver.com/myserver_dev/api/user/login...
https://qa.myserver.com/myserver_qa/api/user/login...
I've tried:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dev.myserver.com/myserver_dev")
.build();
...
#POST("user/login" )
Call<NewUser> login( #Query( "email" ) String email, #Query( "password" ) String password );
but it always give me a 404 saying "Not Found". It only seems to work if I do:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dev.myserver.com")
.build();
...
#POST("server_dev/user/login" )
Call<NewUser> login( #Query( "email" ) String email, #Query( "password" ) String password );
Mainly I would just like to be able to quickly switch servers without having to manually edit two different fields. (One for baseUrl and one for the directory.)
Thanks for your time. :)
It appears retrofit ignores the path component of the baseUrl unless it ends in a trailing slash.
Try --
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://dev.myserver.com/myserver_dev/")
.build();
By the way, there is an issue filed on this already -- https://github.com/square/retrofit/issues/1049
I suggest you to use Dynamic Urls or Passing a Full Url
# Example 3 — completely different url
base url: http://futurestud.io/api/
endpoint: https://api.futurestud.io/
Result: https://api.futurestud.io/
# Example 4 — Keep the base url’s scheme
base url: https://futurestud.io/api/
endpoint: //api.futurestud.io/
Result: https://api.futurestud.io/
# Example 5 — Keep the base url’s scheme
base url: http://futurestud.io/api/
endpoint: //api.github.com
Result: http://api.github.com
In your case:
String SCHEME = "https:";
String SERVER_URL= "//{subdomain}.myserver.com/myserver_dev/";
String BASE_URL= SCHEME + BASE_URL;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.build();
#POST(SERVER_URL + "user/login")
Observable<NewUser> createNewUser(#Path("subdomain") String subdomain, #QueryMap HashMap<String, String> params);
Call:
HashMap<String, String> params = new HashMap<>();
params.put("email",email);
params.put("pass",pass);
Observable<NewUser> observable = mApiService.createNewUser("dev",params);
Related
I am developing an app where users can post text, img or video. Everything working fine. But sometimes it's giving me the error Unprocessable Content, when I want to post a single letter or emoji.
ERROR:: Response{protocol=http/1.1, code=422, message=Unprocessable Content, url=http://myUrl.com}
My RetrofitBuiler Object:
var gson: Gson = GsonBuilder()
.setLenient()
.setDateFormat("yyyy-MM-dd hh:mm:ss.S")
.create()
private var httpClient =
OkHttpClient.Builder().retryOnConnectionFailure(true).connectTimeout(60, TimeUnit.SECONDS)
.build()
private val retrofit: Retrofit by lazy {
Retrofit.Builder().baseUrl(getBaseUrl())
.addConverterFactory(GsonConverterFactory.create(gson))
.addConverterFactory(NullConvertfactory()).client(httpClient).build()
}
val API_SERVICE: FansApiService by lazy {
retrofit.create(FansApiService::class.java)
}
APi InterFace:
#Headers("Accept:application/json")
#Multipart
#POST("endurlHere")
fun createPost(
#Header("Authorization") token: String,
#Part("text_content") text_content: RequestBody,
#Part imageList: List<MultipartBody.Part>
): Call<CreatePostResponse>
You have to encode emoji / or any non textual content for that matter in "UNICODE". Send them to server as UNICODE string and when displaying them decode them back.
Here's the reference link that can help you get started.
i am using okhttp (not retrofit) to make all my request to the api. It's working perfectly but i am having some trouble to make dynamique header. here is what i did :
private fun buildRequest(url: String, methode: Method = Method.GET, filters: Map<String, String> = mapOf(): Request? {
var builder = FormBody.Builder()
builder.add("body", "test")
val request = Request.Builder()
.url(url)
.addHeader("API-Key", apikey)
.post(formBody)
.build()
}
Problem is that i got a map filter that represent some header i need to add, but those are not hard coded but they are dynamique, it can be for exemple :
var filters = mapOf("limit" to "10", "sort" to "date")
But i can't do a static addHeader for the filters because i don't know if i am going to have some or not or which are they going to be.
My idea was to use newBuilder like this :
if (!filters.isNullOrEmpty()){
filters.forEach{
request.newBuilder()
request.addHeader(it.key, it.value)
.build()
}
Problem is that this doesn't add my new header to the call. I am I missing something on how to use newBuilder ? or is there a way to manage dynamique header with okhttp ?
You can use toHeaders() extension function of map to convert your map object to Headers.
All key-value pairs of the map can be easily added to headers like this
val request = Request.Builder()
.url(url)
.headers(filters.toHeaders())
Note - Using headers() would replace all previously added headers of
the request builder.
You can also add headers to request builder later, on using newBuilder()
request.newBuilder()
.headers(filters.toHeaders())
Please check this api: https://api.github.com/emojis
This is part of the response:
{
"+1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png?v8",
"-1": "https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png?v8",
"100": "https://github.githubassets.com/images/icons/emoji/unicode/1f4af.png?v8",
"1234": "https://github.githubassets.com/images/icons/emoji/unicode/1f522.png?v8",
"1st_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f947.png?v8",
"2nd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f948.png?v8",
"3rd_place_medal": "https://github.githubassets.com/images/icons/emoji/unicode/1f949.png?v8",
"8ball": "https://github.githubassets.com/images/icons/emoji/unicode/1f3b1.png?v8",
"a": "https://github.githubassets.com/images/icons/emoji/unicode/1f170.png?v8",
"ab": "https://github.githubassets.com/images/icons/emoji/unicode/1f18e.png?v8",
"abacus": "https://github.githubassets.com/images/icons/emoji/unicode/1f9ee.png?v8",
"abc": "https://github.githubassets.com/images/icons/emoji/unicode/1f524.png?v8",
"abcd": "https://github.githubassets.com/images/icons/emoji/unicode/1f521.png?v8",
}
I'd like to convert this response to a list of Emoji.
data class Emoji(
val name: String,
val url: String,
)
Note that the response is a big object and I need a list.
This is how I'm instantiating Retrofit:
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.build()
How could I achieve it?
You didn't attach you Api interface but based on your descriptions you've put List<Emoji> in you api interface which ia going to raise a MalformedJSONException
Use a Map<String, String> instead and if you need a list use responseMap.map{ Emoji(it.key, it.valie) }
This question already has answers here:
"Expected BEGIN_OBJECT but was STRING at line 1 column 1"
(21 answers)
Closed 1 year ago.
I'm trying to send JSON via a POST request to a rest API with Retrofit. The problem I am having is that I cannot seem to figure out/use the type of data(JSONArray, String, INT ...etc) that retrofit wants in order for it to POST to my rest API. As of now, I have only tried to hard code the JSON in a string and parse it to Retrofit in hopes of it POSTing to the rest API and messing around with what type I input I use to give to retrofit to POST
when I try and parse a String I get the following: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $ this error says that I am not parsing JSON. the problem is that I have no idea what to parse.
when I tried to parse either a JSONarray or a JSONobject or any other type of data my apps view would not load and my app would crash.
my code
interface SimpleApi {
#POST("posttest.php")
suspend fun postit(#Body post: String): Phone
}
this is the retrofit API that I. the String value is the one that I believe is giving me trouble, the Phone class is data class I am using for my recylerview.
private fun TestGet() {
val gson = GsonBuilder()
.setLenient()
.create()
val api = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(SimpleApi::class.java)
GlobalScope.launch(Dispatchers.IO) {
val response = api.postit(test)//it wants a JSONarray
//the above wants some kind of JSON to work I was passing Strings instead
try {
//here lies the app logic and recylerview setup
}catch (e: Exception){
println("you messed up the connection some how")
}
}
}
this function is how I am calling my the rest API, parsing and returning the JSON and handling the business logic.
now the variable test has been a few things originally it was just a hardcoded string exactly like this private var test = "[\"text1\", \"text2\", \"text3\"]" and private var test = """["text1", "text2", "text3"]""" , this did not work, I have also tried to implement A GSON converter as stated above this did not work.
thank you for your time.
EDIT
with out the addConverterFactory(GsonConverterFactory.create(gson)) I get the following errors FATAL EXCEPTION: DefaultDispatcher-worker-1 and com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
The line .addConverterFactory(GsonConverterFactory.create(gson)), when applied means that retrofit is treating each payload that you pas as a Json Object. So, when you pass a simple string you get that error.
A possible fix would be to convert your string array into a json array as explained here https://stackoverflow.com/a/10498107/404438.
Also check if the server response is a valid json, You could achieve this by adding logging interceptor.
Here is how you add the interceptor :
first, in your build.gradle:
implementation "com.squareup.retrofit2:retrofit:2.6.0"
implementation "com.squareup.retrofit2:converter-gson:2.6.0"
implementation "com.squareup.okhttp3:logging-interceptor:3.11.0"
Then:
val gson = GsonBuilder()
.setLenient()
.create()
val builder = OkHttpClient().newBuilder()
builder.readTimeout(120, TimeUnit.SECONDS)
builder.connectTimeout(30, TimeUnit.SECONDS)
if (BuildConfig.DEBUG) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BASIC
builder.addInterceptor(interceptor)
}
val client = builder.build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build()
I'm implementing an android application with Retrofit requests and Moshi to parse the respond.
For one of the requests I need Retrofit to not encode the Query, because it includes ":" and the server won't accept "%3A". I use:
#Query(value = "viaList", encoded = true) viaCitiesCode: String
And
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
And ":" stays in URL as it should but instead of getting a JSON respond it returns this respond (I didn't post the whole respond displayed by Network Profile, because of it's size):
‹ ìZ]rÛ8¾JŠû6k©ÀÒo EËŒ#Ù´${œ©©$Ñ4G©éÐNÖ—Ø[
ìÃ^ao³{
Žm€”HJÔŸ'N¦¦”¸,³4»ûk �Oøå+?N§dþÌ�~åÆîÜÿìŽoHðèÆTàÇg$N¸ÓdþèžÀ“ùà’Yñh‘ø9{z9áfsäÒA÷dŸš*£nô#æ/œ"?M„ÐÇBφÎYê¼ÔM�£Š
TB{
s/´[Bü <øâŽÝ'îg¦Úá}”!�ëÊ_»Ð·”_$¹�æSÚ¦#CHX¿e ¦Ñc˜´J¯Jžg´eÑž¡ór²lÍa*Ú)^KåÝ(l\»±;‡Üà^~] úÁ¡õž1…ŸAä' GÊ]²t)$V8ÎÇ�, €Ñ~X¸óþú
]ïÁ' Ò ßu£/ÑÔçX^ÌòÜÝÜé� ¨TÍãtèÎ)lì1N¢Mjf MÞÏâüµ.EÜEADý ñ2eî…F-‡�_ƒ/‡}ž: Šd(A'eL‹î’´kµˆ õ¹±ÈëÕ0¿ˆL¸‡‹ç(‰´÷;°å]×�üžø¨Cd{÷TBljk0 ò‚PA©š©UPv£ °…Òü©‹g–Ù4ßç$…¥€PݱK棇~bæƒCÐ!G!}uB†mèÁ¢Jÿ‹›©àn&7’C, s¦÷mwÌ™g¡Ë4meŸ‘5Ù†“bøw1Å}G5½«÷رLìt [
çØñ Ó³¯œdüɺøù“žÞÞ¤ÎEpÛûbàßo7Ý·}�Ê>
Everything works fine in Insomnia, When I send the URL with disabling the URL encoding.
Thanks for your help and let me know if you need more information.