How to use Retrofit to upload a file with http put - http

I am trying to upload a file with http PUT method,
I tried with OkHttp successfully, but failed with Retrofit.
Here is my codes :
static final String MEDIA_TYPE=“image/jpeg”
// file is a file path
RequestBody requestBody = getRequestBody(file);
OkHttpClient client = getOkHttpClient();
Request request = new Request.Builder()
.url(url)
.put(requestBody)
.build();
okhttp3.Response response = response = client.newCall(request).execute();
private RequestBody getRequestBody(String filePath) {
MediaType contentType = MediaType.parse(MEDIA_TYPE);
return RequestBody.create(contentType, new File(filePath));
}
The code above succeeded.
What is the equivalent of Retrofit ?
I tried and failed :
public interface UploadFileService {
String CONTENT_TYPE = "image/jpeg";
/** base url, just for Retrofit usage demand. */
String BASE_URL = "https://not.used.net/";
/** Must be consistent with the following uploadFile annotation. */
String UPLOAD_FILE_HTTP_METHOD = "PUT";
#Multipart
#Headers("Content-Type:" + CONTENT_TYPE)
#PUT()
Observable<Response<MinaResponse<LocalAlbum.DummyResponse>>> uploadFile(#Url String url, #Part RequestBody fileBody);
}

Remove Multipart annotation and apply Body to fileBody,
I succeeded!
#Headers("Content-Type:" + CONTENT_TYPE)
#PUT()
Observable<Response<MinaResponse<LocalAlbum.DummyResponse>>> uploadFile(#Url String url, #Body RequestBody fileBody);

Related

backoffice macro returns 404

i am getting the url 404 not found when loading in a macro.
But then i get in the console a
No HTTP resource was found that matches the request URI 'https://localhost:44351/umbraco/api/prisinformation/produktlista?typ=1&version=0'.No action was found on the controller 'PrisInformation' that matches the name 'produktlista'.
and a
No HTTP resource was found that matches the request URI 'https://localhost:44351/umbraco/api/prisinformation/produktlista?typ=0'.No action was found on the controller 'PrisInformation' that matches the name 'produktlista'.
the code i try to call is this one. no mather how much i try i get this error when calling the macro.
public class PrisInformationController : UmbracoApiController
{
private ILoginService _userService;
private MembershipHelper _membershipHelper;
public PrisInformationController(MembershipHelper membershipHelper, ILoginService userService)
{
_userService = userService;
_membershipHelper = membershipHelper;
}
public void Authorize()
{
if (!_membershipHelper.IsLoggedIn())
{
if (_userService.AddAndOrLoginMember())
{
return;
}
}
throw new HttpException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Page not found").ToString());
}
[HttpGet, HttpPost]
[Route("produktlista/{typ}")]
public HttpResponseMessage Produktlista(int typ = 0, int version = 0)
{
Authorize();
string result = string.Empty;
string apiUrl = ConfigurationManager.AppSettings["ApiUrl"];
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl + "/databoken/get/produktlista/" + typ + "/" + version);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
var response = request.GetResponse();
string s = string.Empty;
using (var sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
}
I read it as your Produktlista method has a route defined that requires you to do /umbraco/api/prisinformation/produktlista/1 where 1 is typ, instead of ?typ=1. I could totally be wrong though, but maybe try removing the custom Route definition and see if that helps?
https://our.umbraco.com/Documentation/Reference/Routing/Umbraco-API-Controllers/index-v8
On another note you can change your controller to be of type UmbracoAuthorizedApiController which will do the backoffice auth check for you. Just note that it will change the standard route to be /umbraco/backoffice/api/... instead.

Spring Resttemplate : how to post file and common String data at the same time

I meet a request to upload files with spring resttemplate to upload files
with http header "multipart/form-data", also some other normal parameters need to be posted. how to implements that?
you can use the following code in your application to have both multipartfile and normal request parameters at the same time.
Replace the url with your own.
replace param and value according to your normal parameters.
String url ="http://example.com";
String fileAbsPath ="absolute path of your file";
String fileName = new File(fileAbsPath).getName();
Files.readAllBytes(Paths.get(fileAbsPath));
MultiValueMap<String, Object> data = new LinkedMultiValueMap<String, Object>();
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(Paths.get(fileAbsPath))) {
#Override
public String getFilename() {
return fileName;
}
};
data.add("file", resource);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("file","application/pdf");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("param1", "value1")
.queryParam("param2", "value2")
HttpEntity<> entity =
new HttpEntity<> (data, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result =restTemplate.exchange(
builder.toUriString(),
HttpMethod.POST,
entity,
String.class);
System.out.println(result.getBody());
you can use this code.
HttpHeaders headers = getCASHeaders(MediaType.MULTIPART_FORM_DATA);
LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("fileField", new FileSystemResource(""));//get file resource
params.add("stringfield", stringPayload);
HttpEntity requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<CasAssetApiResponse> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
This will send post call with two param, you can add more according to your wish.
Please have a look at this stackoverflow answer as well
I got the error "cannot be cast to java.lang.String" although my code does not have any casting.

Basic Authentication with Retrofit

I am trying to build a client for a REST API using Retrofit. The API uses basic auth and I have been unable to authenticate using Retrofit.
I tested the API using the curl below and it works as expected
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{some_json}' -u api_key: https://apitest.com/api/v1/customers
Below is the Retrofit client
public interface UserService {
String HOST = "https://apitest.com";
public static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(HOST)
.addConverterFactory(GsonConverterFactory.create());
/*
* CREATE/UPDATE User
*/
#POST("api/v1/customers")
Call<UserAPIResponse> userUpdate(#Body UserUpdateRequest userUpdateRequest);
static UserService newInstance(String userAPIKey) {
String credentials = userAPIKey + ":";
final String basic = "Basic "+ Base64.encodeBase64(credentials.getBytes());
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic);
requestBuilder.header("Accept", "application/json");
requestBuilder.method(original.method(),original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(BlueshiftUserService.class);
}
When I call updateUser on the UserService
Response<UserAPIResponse> response = UserService.userUpdate(userUpdateRequest).execute();
The response.code is 401 (unauthorized/authentication failed)
The curl command with -u and the same credentials works as expected.
The issue was with the credentials encoding. I wasnt sending it as string.
byte[] encodedAuth= Base64.encodeBase64(credentials.getBytes());
final String basic = "Basic " + new String(encodedAuth);
use these libraries in Gradle file
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.cookpad.android.rxt4a:rxt4a:0.9.0'
compile 'io.reactivex:rxjava:1.0.12'
and put this classes in your project
public class ServiceGenerator {
private static final String TAG = erviceGenerator.class.getSimpleName();
public static final int READ_TIMEOUT = 10000;
public static final int CONNECT_TIMEOUT = 100000;
// No need to instantiate this class.
private ServiceGenerator(){}
public static <S> S createService(Class<S> serviceClass, String
endpoint) {
// Call basic auth generator method without user and pass
return createService(serviceClass, endpoint, null, null); }
public static <S> S createService(Class<S> serviceClass, String
endpoint, String username, String password) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
// Set endpoint url and use OkHTTP as HTTP client
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(endpoint)
.setConverter(new GsonConverter(new Gson()))
.setClient(new OkClient(okHttpClient));
if (username != null && password != null) {
// Concatenate username and password with colon for authentication
final String credentials = username + ":" + password;
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// Create Base64 encoded string
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", string);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass); } }
and this interface
public class TodolyClient {
private static final String TAG = TodolyClient.class.getSimpleName();
public static final String ENDPOINT = "your base URL";
public interface TodolyService {
#GET("/wp-json/wc/v2/products")(your remaining url)
Observable<Object> isAuthenticated();
}
}
and call the below method in your main activity
private void createProject() {
final TodolyClient.TodolyService service =ServiceGenerator.createService(
TodolyClient.TodolyService.class, TodolyClient.ENDPOINT, "your user name",
"your password");
Observable<Object> observable = service.isAuthenticated();
AndroidCompositeSubscription compositeSubscription = new AndroidCompositeSubscription();
observable
.lift(new OperatorAddToCompositeSubscription<Object>(compositeSubscription))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onNext(Object project) {
android.util.Log.d(TAG, "onNext: "+project.toString());
}
#Override
public void onCompleted() {
android.util.Log.d(TAG, "onNext:commm " );
}
#Override
public void onError(Throwable e) {
android.util.Log.d(TAG, "onNext: eeeeeeeee"+e.getMessage());
}
});
}
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class), You can add any character set for encoding as the third parameter here.
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/

spring mvc http proxy

I would like to write a spring MVC Controller class that just take any http request in input, add basic authentication headers to it and forward this request to another server.
I try something like this without success.
#Controller
#RequestMapping("/proxyws")
public class ProxyController {
#RequestMapping("/**")
#ResponseBody
public String mirrorRest( #RequestBody String body, HttpMethod method, HttpServletRequest request, HttpServletResponse response) throws URISyntaxException
{
String server = "localhost";
int port = 8080;
URI uri = new URI("http", null, server, port, request.getRequestURI(), request.getQueryString(), null);
RestTemplate restTemplate=new RestTemplate();
HttpEntity entity = new HttpEntity<String>(body);
String plainCreds = "APP_CLIENT:APP_PASSWORD";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
entity.getHeaders().add("Authorization", "Basic " + base64Creds);
ResponseEntity<String> responseEntity = restTemplate.exchange(uri, method, entity, String.class);
return responseEntity.getBody();
}
For a GET method in input, I get the following exception :
org.springframework.http.converter.HttpMessageNotReadableException: Required request body content is missing:
org.springframework.web.method.HandlerMethod$HandlerMethodParameter#8051792a
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleEmptyBody(RequestResponseBodyMethodProcessor.java:189)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:170)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
For a POST request, I get other trouble with le basic auth headers:
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1342)
at org.springframework.http.HttpHeaders.add(HttpHeaders.java:831)
Thanx for your help!
You cannot modify the headers of the HttpEntity object once it's instantiated. You need to pass your headers in through a different HttpEntity constructor, e.g.
public HttpEntity(T body, MultiValueMap<String, String> headers) {
this.body = body;
HttpHeaders tempHeaders = new HttpHeaders();
if (headers != null) {
tempHeaders.putAll(headers);
}
this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);
}
Note the initialization of this.headers: that's where the read-only copy is created.

Read http post headers

Hi I am having trouble I am trying to learn restful services.I created a web service using jax-rs which is shown below
#Path("/users")
public class Welcome {
#POST
#Consumes("text/xml")
#Produces("text/xml")
public Response welcome(String incomingXML){
return Response.status(200).entity("timestamp : " + incomingXML).build();
}
}
I use the following test client to test the service
public class TestService {
public static void main(String args[]) throws ParserConfigurationException, SAXException, IOException {
ClientConfig config = new DefaultClientConfig();
Client client=Client.create(config);
WebResource service=client.resource(getBaseURI());
String urlString = "http://localhost:8080/JaXRSDemo/rest/users";
URL url = new URL( urlString );
HttpURLConnection con = (HttpURLConnection) url.openConnection();
// set up url connection to get retrieve information back
con.setRequestMethod( "POST" );
con.setDoInput( true );
// stuff the Authorization request header
byte[] encodedPassword = ( userName + ":" + password ).getBytes();
con.setRequestProperty( "Authorization",encodedPassword.toString() );
Customer customer=new Customer();
customer.setName("noobstre");
customer.setPin(123455);
ClientResponse response=service.path("rest").path("users").type(MediaType.APPLICATION_XML).post(ClientResponse.class,customer);
System.out.println(" response " + response.getEntity(String.class));
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/JaXRSDemo").build();
}
}
I want to use the password in the header at the server side and do a lookup with the database.The problem I am facing is how do I read the headers at the server.
I'm not very familiar with Jax-RS, but you might use the following methods to get the header information you're looking for:
1.) Use #HeaderParam
/**Server side******/
#Path("/users")
public class Welcome {
#POST
#Consumes("text/xml")
#Produces("text/xml")
public Response welcome(String incomingXML, #HeaderParam("Authorization") String authString)
{
//Use authString here
return Response.status(200).entity("timestamp : " + incomingXML).build();
}
}
2.) Use #Context
/**Server side******/
#Path("/users")
public class Welcome {
#POST
#Consumes("text/xml")
#Produces("text/xml")
public Response welcome(String incomingXML, #Context HttpHeaders headers)
{
//Get Authorization Header
String authString = headers.getRequestHeader("Authorization").get(0);
return Response.status(200).entity("timestamp : " + incomingXML).build();
}
}
Hope this helps!
I solved it using Jersey Client
//clientside
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
final String userName = "admin";
final String password = "admin";
String cred = userName + ":" + password;
WebResource service = client.resource(getBaseURI());
Customer customer = new Customer();
customer.setName("noob");
customer.setPin(123455);
ClientResponse response = service.path("rest").path("users")
.accept(MediaType.APPLICATION_XML)
.header("Authorization", cred)
.post(ClientResponse.class, customer);
System.out.println(" response " + response.getEntity(String.class));
At the server side
#Path("/users")
public class Welcome {
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response welcome(String incomingXML, #Context HttpHeaders headers) {
String s = headers.getRequestHeaders().getFirst("authorization");
return Response.status(200).entity("timestamp : " + incomingXML + s)
.build();
}
}

Resources