In Get Method:
http://xyz.erprnd.com/api/v1/customers/get?yearmonth=201807
My design interface:
#Headers({ "Content-Type: application/json;charset=UTF-8"})
#GET("customers/{get}/{yearmonthValue}")
Call<CustResponse> CustomerData(#HeaderMap Map<String, String> headers,
#Path("get") String get,
#Query("yearmonth") String yearmonth,
#Path("yearmonthValue") String yearmonthValue,
#Header("Authorization") String authHeader);
What can I change to make this work properly?
First, double check that you are passing "http://xyz.erprnd.com/api/v1" as your baseUrl when building Retrofit.
Then, base on the URL you posted, the interface should look something like:
#Headers({ "Content-Type: application/json;charset=UTF-8"})
#GET("customers/get")
Call<CustResponse> CustomerData(#HeaderMap Map<String, String> headers,
#Header("Authorization") String authHeader,
#Query("yearmonth") String yearmonth);
when you define query parameters, you just need to add the annotation #Query("param_name") and then the value of the variable passed in will be transform intro: param_name=variable_value
Also, I removed your #Path("get") parameter, since it seems that that part of the URL will always be /get and won't change.
Unfortunately, I cannot test it since I don't have authorization to your API.
Related
I have two strings that I should set them in body for my put request. How can do it with retrofit?
#PUT("/user-management/Account/activate")
#FormUrlEncoded
#Headers({ "Content-Type: application/json"})
Call<Verification> activation(#Part("code") String code , #Part("token") String token);
You may try similar code I posted below: For detailed code please post your context or a part of your code.
#Multipart
#PUT("user/photo")
Call<User> updateUser(#Part("photo") RequestBody photo, #Part("description") RequestBody description);
You can pass multiple Strings in Body like this:
Create a Class
public class Verification
{
public String code;
public String token;
}
Set the data to object
Verification loginCredentials = new Verification();
loginCredentials.code= "12345;
loginCredentials.token= "54321";
Call your api
#PUT("/user-management/Account/activate")
Call<Verification> activation(#Body Verificationcredentials);
I am writing a client-server Android application. I need to send a file created by user (photo) to server via POST request. The problem is, that when i try to send a file, i can't add a POST Field to my request. Maybe I'm wrong fundamentally, and this operation should be done another way?
#FormUrlEncoded
#Multipart
#POST("/answer/add-file")
Call<AbstractServerResponse> sendSingleFile(#Query("access-token") String accessToken,
#Query("w") String screenWidth,
#Field("answer_id") Integer answerId,
#Part("file") File fileToUpload);
When i try to send files in a multipart way only, i get an exception:
java.lang.IllegalStateException: JSON must start with an array or an object.
As I understand, this happends because the body (main part) of the request is empty.
Multipart requests are used when #Multipart is present on the method. Parts are declared using the #Part annotation.
------ from http://square.github.io/retrofit/
I'm using #Multipart in my project like this:
#POST("/{action}")//POST 多个文件
#Multipart
public void PostAPI(
#Path(value = "action", encode = false) String action,
#Part("path") TypedFile[] typedFiles,
#PartMap Map<String, String> params,
Callback<APIResponse> callback);
Maybe u can try this:
#Multipart
#POST("/answer/add-file")
Call<AbstractServerResponse> sendSingleFile(
#Query("access-token") String accessToken,
#Query("w") String screenWidth,
#Part("answer_id") Integer answerId,
#Part("file") File fileToUpload);
You cannot use both #FormUrlEncoded and #Multipart on a single method. An HTTP request can only have one Content-Type and both of those are content types.
I wanna send a list of integer with userName and password to WebService some thing like bellow request
UpdateDocumentState(List<int> documentIds, string userName, string password)
But I don't know How to do that ? Use #Post Or #Put ? use #Query Or #Field ? I googled but didn't find any good example or tutorial which explained these well. ( All tutorial I found was about #GET )
could anyone give me some piece of code , how to do that ?
About the use of #PUT or #POST I think you had to get this information from the WebService developers.
Anyway, here sample code for both of Retrofit annotations with or without Callback response.
#POST("your_endpoint")
void postObject(#Body Object object, Callback<Response> callback);
#PUT("/{path}")
String foo(#Path("path") String thePath);
EDIT:
Object is a custom class which represent the data you had to send to the WebService.
public class DataToSend {
public List<Int> myList;
public String username;
public String password;
}
For example when the #POST annotation declaration will be:
#POST
void postList(#Body DataToSend dataToSend, Callback<Response> callback);
and then you call the method using Retrofit service
yourService.postList(myDataToSend, postCallback);
I am using an API that uses an authorization scheme that requires a special "X-Authorization" header to be set to authenticate the request. For example, this Retrofit setup works perfectly for the user whose auth token is abc123:
#Headers("X-Authorization: abc123")
#GET("/posts")
Observable<List<Post>> get_posts();
I cache the user's X-Authorization token, so I have access to that, however, I can't just drop it in the #Headers declaration.
#Headers("X-Authorization: " + token)
#GET("/posts")
Observable<List<Post>> get_posts();
I get a compile error here: Error:(41, 34) error: element value must be a constant expression
Any ideas on how I could get around this?
Since Retrofit 2.0 you have two options
1) Using OkHttp 2.2+ use Interceptor
At the Http level, you have more control over the request, so you could do things like applying headers only to a specific request made to a specific endpoint, and so on.
public class MyOkHttpInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (!"/posts".contains(originalRequest.url()) ) {
return chain.proceed(originalRequest);
}
String token = // get token logic
Request newRequest = originalRequest.newBuilder()
.header("X-Authorization", token)
.build();
return chain.proceed(newRequest);
}
[...]
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new MyOkHttpInterceptor());
OkClient okClient = new OkClient(okHttpClient);
YourApi api = new RestAdapter.Builder()
.setEndpoint(url)
.setClient(okClient)
.build()
.create(YourApi.class);
Edit:
Adding #JakeWarthon comment as another option as is also valid.
2) Put #Header on a method parameter and pass it as a value when invoking.
From the docs:
// Replaces the header with the the value of its target.
#GET("/")
void foo(#Header("Accept-Language") String lang, Callback<Response> cb);
Header parameters may be null which will omit them from the request. Passing a List or array will result in a header for each non-null item.
Note: Headers do not overwrite each other. All headers with the same name will be included in the request.
EDIT: This option should not be considered as Retrofit 2.* dropped support for interceptors.
3) User retrofit RequestInterceptor
From the docs:
Intercept every request before it is executed in order to add additional data.
You could do something like
public class MyRetrofitInterceptor implements RequestInterceptor {
#Override
public void intercept(RequestFacade req) {
String token = // get token logic
if (token != null) {
req.addHeader("X-Authorization", token);
}
}
[...]
YourApi api = new RestAdapter.Builder()
.setEndpoint(url)
.setRequestInterceptor(new MyRetrofitInterceptor())
.build()
.create(YourApi.class);
The "problem" with this approach is that the interceptor will get executed on all the endpoints, as it's set at the RestAdapter level, and not per endpoint. Also, the RequestFacade doesn't expose much information about the request, so no chance to add much logic around it.
Passing header in parameter would be helpful. Look to the following code;
#GET("/posts")
Observable<JsonElement> getDataFromService(
#HeaderMap Map<String, String> headers,
#QueryMap HashMap<String, Object> queryParams
);
hashMap1.put("Authorization", token);
return ApiService.getAPI_test().getDataFromService(hashMap1, url, hashMap)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io());
Update:
More better would be
#GET("/posts")
Observable<JsonElement> getDataFromService(
#Header("Authorization") token: String = "Bearer " + PreferenceUtils.getToken(),
#QueryMap HashMap<String, Object> queryParams
);
Dynamic Header In Retrofit 2
I have struggled too much to add Dynamic Header In Retrofit 2.
I have gone through so many blogs and StackOver flow. Everyone has shown example with Interceptor.
And it’s not a wise thing ,just for one API call we need to do that much work.
You just have to add #HeaderMap as argument of fun. I have done in very simple way :-
In Kotlin
val headers = HashMap<String, String>()
headers["KEY_AUTHORIZATION"] = "paste AUTHORIZATION value here"
headers["KEY_TOKEN"] = "paste TOKEN value here"
val jsonObject= JsonObject()
I am passing here header and other data also
Calling of fun:-
postEvent(headers,jsonObject)
API Declaration
#POST("/v1/post_data")
fun postEvent(#HeaderMap headers: Map<String, String>, #Body jsonObject: JsonObject): Call<JsonObject>
API Declaration with RxAndroid
#POST("/v1/post_data")
fun postEvent(#HeaderMap headers: Map<String, String>, #Body jsonObject: JsonObject): Single<JsonObject>
2nd argument here i have JsonObject. You can replace with anything whatever you need to pass or you can remove it also.
In Java
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("KEY_AUTHORIZATION","paste AUTHORIZATION value here");
headers.put("KEY_TOKEN", "paste TOKEN value here");
JsonObject jsonObject= new JsonObject();
I am passing here header and other data also
Calling of fun:-
postEvent(headers,jsonObject);
API Declaration
#POST("/v1/post_data")
Call<JsonObject> postEvent(#HeaderMap Map<String, String> headers, #Body JsonObject jsonObject);
API Declaration with RxAndroid
#POST("/v1/post_data")
Single<JsonObject> postEvent(#HeaderMap Map<String, String> headers, #Body JsonObject jsonObject);
2nd argument here i have JsonObject. You can replace with anything whatever you need to pass or you can remove it also.
A request Header can be updated dynamically using the #Header annotation. A corresponding parameter must be provided to the #Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used.
#GET("user")
Call<User> getUser(#Header("Authorization") String authorization)
When the last part of this answer
How to dynamically set headers in Retrofit (Android)
did not work for me (halfway of the project), I improved it:-
public class MyRetrofitInterceptor implements RequestInterceptor {
// volatile variable
public static String token = null; //change at start of app
#Override
public void intercept(RequestFacade req) {
// change token from outside the class.
if (token != null) {
req.addHeader("X-Authorization", token);
}
}
It worked as soon as the token was updated from the response from the server API.
I think it worked as the string variable 'token' was used as the reference to its value, in global terms (being public static).
I am trying to send multiple parameters (as I usually do) with #QueryMap but via POST this time using retrofit.
Retrofit API
#POST("/request.php")
void sendRequest(#QueryMap Map<String, String> parameters, retrofit.Callback<RequestSendResponse> callback);
Map that is being send
public static Map<String, String> parametersSendRequest(Context sender, Request request)
{
Map <String, String> parameters = new HashMap<>();
Operator operator = AppConfig.config().operator;
parameters.put("user_name", request.user_name);
parameters.put("user_surname", request.user_surname);
parameters.put("user_gender", request.user_gender);
parameters.put("user_relationship", request.user_relationship);
parameters.put("user_dob", request.user_dob);
parameters.put("operator_name", operator.name);
parameters.put("request_photoid", request.request_photoid);
parameters.put("request_user_content", request.request_user_content);
parameters.put("request_title", request.request_title);
parameters.put("uuid", UUID(sender));
parameters.put("response_type", "json");
parameters.put("platform", "android");
parameters.put("mode", "send");
return parameters;
}
Server result
{"POST":[],"GET":{"operator_name":....}}
I can see that even the method is sent to POST, #QueryMap causes these parameters to be sent over GET. Even when I use #Body instead of #QueryMap, retrofit converts my #QueryMap to a JSON object, which is not I want.
All I want to do is to send param1=value1¶m2=value2 on my request body, instead of a JSON object (Using my Map<String, String>)
to send parameters using POST (#FormUrlEncoded and #FieldMap)
#FormUrlEncoded
#POST("/request.php")
void sendRequest(#FieldMap Map<String, String> parameters, retrofit.Callback<RequestSendResponse> callback);
This one works for me
#FormUrlEncoded
#POST("/profile/")
void getUserProfile(#Field("whatever")String whatever, Callback<Response> callback);
Pay special attention to the final slash after "profile". I had problems because I was not adding it. Hope it helps.