Strava V3 API Upload Using Scribe (on Google App Engine)

1.1k views Asked by At

I am trying to use Scribe to upload a GPX file (not gzipped) to Strava using their V3 API (with Java, in Google App Engine):

String url = "https://www.strava.com/api/v3/uploads?access_token=<TOKEN>";
OAuthRequest req = new OAuthRequest(Verb.POST, url);
req.addQuerystringParameter("private", "1");
req.addQuerystringParameter("activity_type", "bike");
req.addQuerystringParameter("data_type", "gpx");
req.addQuerystringParameter("external_id", <Unique String>);

req.addHeader("Content-Type", "multipart/form-data");
String gpx = <Content of GPX file to Upload>;

req.addBodyParameter("file", gpx);

Response response = request.send();

Result is that I get a response code 500 (Internal Error) from Strava, and it doesn't upload the GPX activity.

I guess this is a problem to do with how I am forming the HTTP multipart POST, which is defined in the Strava documentation here as:

DEFINITION
POST https://www.strava.com/api/v3/uploads
EXAMPLE REQUEST
$ curl -X POST https://www.strava.com/api/v3/uploads \
-F access_token=83ebeabdec09f6670863766f792ead24d61fe3f9 \
-F activity_type=ride \
-F [email protected] \
-F data_type=fit


Parameters:
<OTHERS>
file: multipart/form-data required 
the actual activity data, if gzipped the data_type must end with .gz

Any ideas about how I can make this work please? Thank you.

EDIT: Discovered several things with my own further investigations:

  • Scribe is very much just about signing oauth, so the author is not focusing on adding functionality to handle multipart/form-data (although people have suggested such additions)
  • I could use one of the Apache classes (MultipartEntity) to do this, with Scribe, except that I think that Apache library is not supported under Google App Engine. See this thread, which would be perfect, except for the Apache / GAE problem
2

There are 2 answers

0
David George On BEST ANSWER

This is a complete solution. Pass your bearer token and filename to upload. This is for FIT files but would be a simple change for GPX. Taken from here:

https://github.com/davidzof/strava-oauth/

public static long uploadActivity(String bearer, String fileName) {
    JSONObject jsonObj = null;

    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(
            "https://www.strava.com/api/v3/uploads");
    httpPost.addHeader("Authorization", "Bearer " + bearer);
    httpPost.setHeader("enctype", "multipart/form-data");

    MultipartEntity reqEntity = new MultipartEntity(
            HttpMultipartMode.BROWSER_COMPATIBLE);
    try {
        reqEntity.addPart("activity_type", new StringBody("ride"));
        reqEntity.addPart("data_type", new StringBody("fit"));
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    FileBody bin = new FileBody(new File(fileName));
    reqEntity.addPart("file", bin);

    httpPost.setEntity(reqEntity);

    HttpResponse response;
    try {
        response = httpClient.execute(httpPost);

        HttpEntity respEntity = response.getEntity();

        if (respEntity != null) {
            // EntityUtils to get the response content
            String content = EntityUtils.toString(respEntity);
            System.out.println(content);
            JSONParser jsonParser = new JSONParser();
            jsonObj = (JSONObject) jsonParser.parse(content);
        }
    } catch (ParseException | IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 

    return (long) jsonObj.get("id");
}
0
nickpharris On

Ultimately I found this solution on Stack Overflow, which provided the way to use the Apache class

MultipartEntity

within the constraints of Google App Engine. I just had to add three Apache JARs to my GAE project: httpclient-4.3.1.jar, httpcore-4.3.jar and httpmime-4.3.1.jar.

And I then combined with this solution that allowed me to add a

FileBody

to the

MultipartEntity

(in my case a GPX "file" I had constructed in a String). Together the two solutions worked perfectly!