0

Hi I'm primarily an Android developer and am pretty clueless about http protocols, you help would be much appreciated!

I am trying to make an api call to this: http://api.haikutest.com/developer/apidoc/assignments.html where I POST a file on the device.

They give a sample request of:

POST /api/assignments/3/submit
message[subject]=Subject+of+the+message&message[body]=Some+long+text&message[sent_at]=2013-07-05&message[draft]=0&message[assignment_id]=3&files[][file]=%23%3CFile%3A0x007ff59c9c1de8%3E&files[][filename]=test.pdf

And in the description state that the files param is:

Array of files with each element containing a hash of filename and base64 encoded file

This is the code that I'm trying right now (note: I'm using Robospice + Spring for Android):

   File file = new File(Environment.getExternalStorageDirectory() +
                "/DCIM/Camera/1357279228432.jpg");
        Base64InputStream stream = new Base64InputStream(new FileInputStream(file), 0);
        HttpHeaders headers = new HttpHeaders();
        headers.add("x-haiku-auth", HaikuAPI.getAuthHeader());
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
        parts.add("files[][file]", parts);
        HttpEntity<Object> request = new HttpEntity<Object>(stream, headers);
        UriComponentsBuilder builder = UriComponentsBuilder
                .fromUriString(
                        "https://" + HaikuAPI.getDomain() + "/api/assignments")
                .pathSegment(assignmentID + "", "submit")
                .queryParam("message[subject]", "Assignment Completed")

                .queryParam("message[body]", message)
                .queryParam("message[assignment_id]", assignmentID)
                .queryParam("files[][filename]", "test.jpg");

        URI url = builder.build().toUri();

        String response = getRestTemplate().postForObject(url, request, String.class);
        return response;

But I get an error saying that it can't serialize the stream to JSON. Following the API documentation do I have to place the stream as a param? Also what is the correct way to implement this? I would love if I didn't have to put a file size limit on the user, hence the streams. Though I have gotten it to work with small files encoded in Base64 and placed directly as a param...

Any help is greatly appreciated! I will definitely not downvote comments or answers for small pointers.

Updated

Updated code, but still get another error message:

00:25:50.904 Thread-2066 An exception occurred during request network execution :Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [application/x-www-form-urlencoded]
2
  • 1
    I'm not quite sure, but I doubt you can stream a file over, if the service expects you to simply send 1 complete request Commented Aug 6, 2013 at 6:21
  • @stefan the sample request has the word file in it and is extremely short for a PDF... How did they do that? Commented Aug 6, 2013 at 6:30

1 Answer 1

1

Looks like you're using Spring for Android. Judging that error message it seems Spring forces the content type to be application/json, while I believe you're trying to send application/x-www-form-urlencoded. So set this Content-Type header:

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

Spring will know then to match the proper MessageConverter. More info on this here.

EDIT: Also, you're supposed to send the request data in POST data, not in request URI. Move that to a MultiValuesMap. Have a look at the link I gave you how to post such data. A complete documentation on these can also be found here.

EDIT2 You need to set the MessageConverter for your response as well. Something like:

List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
headers.setAccept(acceptableMediaTypes);

EDIT3 If you need to send files, consider using Resource, to be more specific InputStreamResource. But there is a trick: you need to provide the file name and the file size, otherwise your request will crash. Something like:

Resource res = new InputStreamResource(context.getContentResolver().openInputStream(itemImage)) {
                @Override
                public String getFilename() throws IllegalStateException {
                    return fileInfo.getFileName();
                }

                @Override
                public long contentLength() throws IOException {
                    return fileInfo.getFileSizeInBytes();
                }
            };
Sign up to request clarification or add additional context in comments.

12 Comments

Thank you I'll try it out when I get home
I tried this but it didn't work... I updated my question to reflect this. What am I doing wrong?
It's all a matter of finding the corresponding MessageConverter for what you're sending. Can you try headers.setContentType(MediaType.TEXT_PLAIN);?
... and then you need to set the corresponding MessageConverter for response. Edited my answer for that.
What was the problem/solution?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.