I have to make a post request using retrofit, but the URL for this request comes from another request (GET), and the URL comes as a complete endpoint (i.e: https://pod-000-1005-03.backblaze.com/b2api/v2/b2_upload_file?cvt=c001_v0001005_t0027&bucket=4a48fe8875c6214145260818).
How can i make a retrofit request directly to this endpoint?
How im creating the retrofit instance:
fun getUploadApi(uploadUrl: String): B2UploadApi {
return Retrofit.Builder()
.baseUrl(uploadUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(B2UploadApi::class.java)
}
this throws an exception since the url doesnt end with '/'
And the POST request:
#POST
suspend fun uploadFile(
#Header("Authorization") authToken: String,
#Header("X-Bz-File-Name") fileName: String,
#Header("Content-Length") fileSize: Int,
#Header("Content-Type") mimeType: String,
#Header("X-Bz-Content-Sha1") sha1: String,
#Body byteArray: ByteArray
): Response<UploadResponse>
As mentioned in documentation , #url will override base url which you have mentioned at time of retrofit object creation
So you just need to use #url annotation along with method in retrofit service
documentation - https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Url.html
example -
https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests
I want to pass JSON array inside body in Retrofit.
contacts: [{fullName: "foo", email: "abc#gmail.com", countryCode: "00", phoneNumber: "00000000"}]
This is how I am doing it
#FormUrlEncoded #POST("office/templates/send/{id}")
fun sendTemplates(
#Header("Authorization") accessToken: String?,
#Field("contacts[]") contacts: List<SendDocumentModel>,
#Path("id") id: String?):
Call<BaseResponse<TemplatesResponse>>
Change Call< BaseResponse< TemplatesResponse >> to Call< JsonArray > with using the library of com.google.gson.JsonArray
I am creating a retrofit get request where i need to pass a data base query and some spacial character like '$' in URL in kotlin. But I am getting error.
java.lang.IllegalArgumentException: URL query string must not have replace block. For dynamic query parameters use #Query.
This is URL which I am using in postman but cant in retrofil
https://someURL.com?customParam=true&pageSize=100&query=$filter=(drivercell eq'1111111119')$orderby=creationTimedesc&withTotalPages=true
This is the code of calling retrofit method
val restServiceModel = DRestServiceModel.create()
val model = restServiceModel.getTripsData("Basic bWs6SU9UMTIzNCM=", "application/json", "\$filter=(drivercell%20eq'1111111119')")
This is method
#GET("inventory/managedObjects?customParam=true&pageSize=100&{query}\$orderby=creationTimedesc&withTotalPages=true")
fun getTripsData(#Header("Authorization") token: String, #Header("Content-Type") contentType: String, #Query("query", encoded = true) query : String): Single<TripsResponseModel>
Please help me.
Problem is you are trying to put Path param in a middle of a query while supplying it via another Query. You should rework your request. Try something like:
#GET("inventory/managedObjects")
fun getTripsData(#Header("Authorization") token: String,
#Header("Content-Type") contentType: String,
#Query("customParam") customParam: Boolean?,
#Query("pageSize") pageSize: Int?,
#Query("query", encoded = true) query: String,
#Query("withTotalPages") withTotalPages: Boolean?): Single<TripsResponseModel>
And use it like:
val model = restServiceModel.getTripsData("Basic bWs6SU9UMTIzNCM=", "application/json", true, 100, "your query_goes here", true)
This way should it work.
#Headers("Accept: application/json")
#POST("/api/v1/search/filter")
#FormUrlEncoded fun searchFilter(#Field("leaf_id") leaf_id: Int,
#Field("lang") lang: String,
#Field("token") token: String,
#Field("ud_id") ud_id: String,
#Field("min_price") min_price: Float,
#Field("max") max: Float,
#Field("page") page: Int,
#Field("per_page") per_page: Int,
#Field("properties") properties:JSONObject): Observable<RespProductsInCatg>
here in the #Field("properties") I'm trying to send json object but getting failed response.
In Postman its returning proper response
Try to use a data class for parameters to be passed in properties field.
Then pass an object of that data class, and use #Body instead of #Field for properties.
Try creating whole request as an object and add the same as #Body param without using #Field values.
Something like
data class Request(var leaf_id:Int,
var lang: String,
.
.
.
var properties: List<Property>);
and
data class Property(var param1:Int, .... );
construct the Request Object and try adding just that as #Body param.
I am trying to make POST request using the Retrofit 2. The request type is form-data NOT application/x-www-form-urlencoded.
I am only posting data not the files in the request and the response is in the form of JSON.
I have tried #FormUrlEncoded, #Multipart but it is not working.
I have tried following request
1. First Attempt
#FormUrlEncoded
#POST("XXXX")
Call<PlanResponse> getPlanName(#Field(Constants.ACTION_ID) String actionId, #Field(Constants.OFFER_CODE) String offerCode);
2. Second Attempt
#Headers({"Content-Type: multipart/form-data","Content-Type: text/plain"})
#FormUrlEncoded
#POST("XXXX")
Call<PlanResponse> getPlans(#Body #FieldMap(encoded = false) Map<String, String> data);
3. Third Attempt
#Headers("Content-Type: multipart/form-data")
#Multipart
#POST("XXXX")
Call<PlanResponse> myPlans(#Part(Constants.ACTION_ID) String actionId, #Part(Constants.OFFER_CODE) String offerCode);
I am only getting the body as null. It is working with the POSTMAN.
I have also search about form-data and application/x-www-form-urlencoded and found that if the data is binary then use form-data and if data is ASCII then use application/x-www-form-urlencoded
I am trying find Is form-data is not supported by the Retrofit?
POSTMAN request
Cache-Control: no-cache
Postman-Token: XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX-XXXXXXXXXXXX
Content-Type: multipart/form-data; boundary=---- WebKitFormBoundaryXXXXXXXXXXXX
----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="actionId"
1000
----WebKitFormBoundaryXXXXXXXXXXXX
Content-Disposition: form-data; name="offerCode"
MYCODE
----WebKitFormBoundaryXXXXXXXXXXXX
I can only add HTTP Generated code snipped from POSTMAN
Here's another Solution using request body:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("param1", param1)
.addFormDataPart("param2", param2)
.build();
apiInterface.somePostMethod(requestBody).enqueue(
//onResponse onFailure methods
);
here's my api inteface POST method
#POST("somePostMethod")
Call<ResponseBody> somePostMethod(#Body RequestBody body);
Hope it helps.
In retrofit 2.0 to perform POST request like above, you should use RequestBody type for your parameter like this.
#Multipart
#POST("XXXX")
Call<PlanResponse> myPlans(#Part(Constants.ACTION_ID) RequestBody actionId, #Part(Constants.OFFER_CODE) RequestBody offerCode);
And here how to get requestBody from String.
String somevalue = "somevalue";
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), somevalue);
I wanted to pass an array of ids to an existing request.
I tried several variants from here, Retrofit - Send request body as array or number, How to send PUT request with retrofit string and array list of model I need to use URL encoded, but they didn't work. Then I tried android retrofit send array as x-www-form-urlencoded.
I added [] to a list parameter and List to it's type:
#FormUrlEncoded
#POST("your_request/")
fun sendIds(
#Field("token") token: String,
#Field("city_id") cityId: Int?,
#Field("description") description: String,
#Field("ids[]") ids: List<Int>? // Add '[]' here.
): Deferred<YourResponse>
Then called it as usual (with Kotlin coroutines):
api.sendIds("f0123abc", null, "description", listOf(1, 2, 3)).await()
See also Is it possible to send an array with the Postman Chrome extension? to understand how it looks like in Postman.
form-data is supported for sure.
I will make you clear using an example of typical signup process.
First of all add a header
#FormUrlEncoded
in your user client.
Use
#FieldMap
instead of direct objects. So your user-client code will something like this
#POST("signup/")
#FormUrlEncoded
Call<ResponseModel> signup(#FieldMap Map<String,String> params);
Now in your main activity, make a Hashmap all of your data like this,
Map<String,String> params = new HashMap<String, String>();
params.put("fullname", fullname);
params.put("city", city);
params.put("state",state);
params.put("address",address);
params.put("email",email);
params.put("password1", password1);
params.put("password2", password2);
Now simple pass this hashmap into the method like this
Call<ResponseModel> call = service.signup(params);
call.enqueue(new Callback<ResponseModel>() {
#Override
public void onResponse(Call<ResponseModel> call, Response<ResponseModel> response) {
if (response.isSuccessful()) {
Toast.makeText(SignUp.this,response.body.getData,Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SignUp.this, "Error : ", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseModel> call, Throwable t) {
t.printStackTrace();
Toast.makeText(SignUp.this, "Server Unavailable : "+t.toString(), Toast.LENGTH_SHORT).show();
}
});
Here's another Solution using the request body form-data in Kotlin. This solution work for me in Kotlin.
val request = ServiceBuilder.buildService(TmdbEndpoints::class.java)
val requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("email", "abc#gmail.com")
.addFormDataPart("password", "admin")
.addFormDataPart("push_token", "token")
.addFormDataPart("device_id", "1112222")
.addFormDataPart("platform", "android")
.addFormDataPart("device_name", "my device")
.addFormDataPart("version", "1.2")
.build()
val call = request.userFigLogin(requestBody)
call.enqueue(object : Callback<LoginResult> {
override fun onFailure(call: Call<LoginResult>, t: Throwable) { }
override fun onResponse(call: Call<LoginResult>,
response: retrofit2.Response<LoginResult>) { }
})
You should use RequestBody type for your parameter like this.
#POST("api/login")
fun userFigLogin(#Body body: RequestBody): Call<LoginResult>
For Kotlin, This is another way of doing it. For api that do not accept FormUrEncoded data.
fun login(email: String, password: String, grantType: String):
Single<TokenModel> {
var userNameB:RequestBody=
email.toRequestBody(email.toMediaTypeOrNull())
var passwordB: RequestBody =
password.toRequestBody(password.toMediaTypeOrNull())
var grantTypeB: RequestBody =
grantType.toRequestBody(grantType.toMediaTypeOrNull())
return userApi.loginUSer(userNameB,passwordB,grantTypeB)
.map { TokenModel(it.accessToken, it.refreshToken) }
}
Then.
#Multipart
#POST("auth/token/")
fun loginUSer(
#Part("username") request: RequestBody,
#Part("password") passwordB: RequestBody,
#Part("grant_type") grantTypeB: RequestBody
): Single<Token>
just remove this from header
defaultProperties["Content-Type"] = "application/json"
I think this can help you
#Multipart
#Headers( "Content-Type: application/x-www-form-urlencoded")
#POST("api/register")
fun postRegister(
#Part("authtype") authtype: String,
#Part("channel")channel : String,
#Part("children")children : List<String>,
#Part("names") names: List<String>,
#Part("email") email: String,
#Part("password")password : String,
#Part("name") name: String,
#Part("timezone") timezone: Int,
#Part("timezone_name")timezone_name : String,
#Part("token_device")token_device : String,
#Part("imageData") imageData: String,
#Part("mimeType") mimeType: String,
#Part("extension") extension: String,
): Call<ResponseBase>