6

I'm creating a web app using only HTML5 + Javascript + jQueryMobile and I wanted to upload a file to a Google App Engine web application using a Google Cloud Endpoint, also created by me.

As I control both sides, I can (and want to) create the simplest interaction possible.

As for the Endpoint, I thought of creating a method like this:

@ApiMethod(
  name = "uploadFile",
  path = "upload_file",
  httpMethod = HttpMethod.POST
)
public void uploadFile(File file) {
  //process the file
}

This File class could contain a field fileData of type Blob, or byte[] or something like that, repersenting the file data... Something like:

public class File {    
  private String fileName;
  private long fileSize;
  private Blob fileData;    
  //getters and setters
}

So the first question would be: what's the most suitable type for this field fileData?

And, taking into account the type selected for the field, how could I create the necessary POST request for that endpoint method form Javascript/jQuery?

Basically I need to create a POST request to http://myappid.appspot.com/_ah/api/files/v1/upload_file adding the File object in the POST data.

Note: I'm sorry I haven't tried anything for the Javascript code because I'm not familiar at all with this technologies, so I'd appreciate any help...

MikO
  • 18,243
  • 12
  • 77
  • 109
  • Sorry I wrote a answer for python – topless Apr 09 '13 at 11:10
  • I'd like to see an answer to this. I'm using dart endpoints (but same concept as javascript endpoints client api) and to upload a file I'm having to use a webapp2 handler instead of an endpoints service. This sucks because endpoints.get_current_user() is null when using webapp2 handlers so I'm having to do a work around. – Rusty Rob Mar 13 '14 at 21:57
  • @robertking, I've just added an answer with the code I used, maybe you can find something interesting, although I can't explain too much because I don't remember :) – MikO Mar 13 '14 at 22:24
  • Thanks @MikO . btoa (base64) is an option but some files may be too big. – Rusty Rob Mar 13 '14 at 22:28
  • @robertking, yes sure! This was a little part of my MSc project, and I got a good mark, but it has **lots** of weaknesses :) – MikO Mar 13 '14 at 22:32

2 Answers2

1

Edit: The answer below targes python version of AppEngine

It is a common demand with no clear solution. Till now, gae-init-upload is a demonstration of how you can achieve that with AppEngine and CoffeeScript. Worth having a look, CoffeeScript is being compiled into JavaScript in case you are not familiar.

The JavaScript solution you are looking for is under

/main/static/src/coffee/common/upload.coffee

topless
  • 8,069
  • 11
  • 57
  • 86
  • This is not very helpful. It's pretty easy to upload a file to a normal GAE web application. The difficult part is how to do it through Google Cloud Endpoints. – James Gan Dec 04 '13 at 21:23
1

I eventually used this code in my AMD Javascript application. I'm sorry I cannot explain it too much because I've written a big amount of code since I wrote this project, and as you can see I didn't comment the code properly (fail!!), anyway maybe you can get some ideas...

Note that there's something about getting navigator position because I wanted to store the location where the file was uploaded from, but it's not necessary at all!

Controller.js

    uploadFile: function(request, render) {
        var self = this;
        var file = $("#file").get(0).files[0];

        var reader = new FileReader();            
        reader.onload = function (evt) { 
            var upload = {
                provider: self.folder.provider,
                folderIdentifier: self.folder.id,
                fileName: file.name,
                fileSize: file.size,
                base64Data: btoa(evt.target.result),
                location: {
                    latitude: self.position.coords.latitude, 
                    longitude: self.position.coords.longitude
                }
            }                
            var uploadFilePromise = self.connector.uploadFile(self.sessionToken.token, upload);            
            uploadFilePromise.done(function (file) {
                render("file", {
                    result: "DONE",
                    file: file
                });
            });                
            uploadFilePromise.fail(function (error) {
                render("file", {
                    result: "FAIL"
                });
            });
        }

        navigator.geolocation.getCurrentPosition(function(position) {
            self.position = position;                
            reader.readAsBinaryString(file);
        });
    }

Connector.js

    uploadFile: function (sessionToken, upload) {
        var self = this;
        var promise = new Promise();

        gapi.client.load('upload', 'v1', function() {
            var request = gapi.client.upload.uploadFile({
                session_token: sessionToken, 
                resource: upload
            });
            request.execute(function(response) {
                if (response.error) {
                    promise.reject(response.error);
                }
                else {
                    var file = File.create(response.result.provider,
                                           response.result.type, 
                                           response.result.identifier, 
                                           response.result.name,
                                           response.result.description,                                               
                                           response.result.created,
                                           response.result.size,
                                           response.result.link,
                                           {
                                               latitude: response.result.location.latitude,
                                               longitude: response.result.location.longitude
                                           });
                    promise.resolve(file);
                }
            });
        }, self.api);

        return promise;
    }

Endpoint.java

@Api(name="upload")
public class UploadEndpoint {


    @ApiMethod(
        name = "uploadFile",
        path = "upload_file",
        httpMethod = HttpMethod.POST
    )
    public File uploadFile (
            @Named("session_token") String token, 
            Upload upload) throws InternalServerErrorException {

        File file = new UploadController().uploadFile(token, upload);
        return file;
    }

}
MikO
  • 18,243
  • 12
  • 77
  • 109