4

Ok so this is my problem.. To share an image post via linkedin api, you first have to register your image file, you do that via a post request in which you send your binary file. Then you use the the image URN in the original request to submit your post. My request goes through, returns 201 code (which should be a successful request) but ends up not posting the image or the text. If i try to post only text, it works. I've tried registering my image using curl, and it posted on linkedin, so i think i'm not sending the binary file in a request properly, this is my request:

            HttpClient client = HttpClientBuilder.create().build();
            HttpPut request = new HttpPut(uploadUrl);
            request.addHeader("Content-Type", "data/binary");
            request.setHeader("X-Restli-Protocol-Version", "2.0.0");
            request.setHeader("Authorization", "Bearer " + myToken);

            File file = new File(pictureUrl);

            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            builder.addBinaryBody("upload-file", file);
            request.setEntity(builder.build());
            HttpResponse response = client.execute(request);

I get code 201 with this code, but it still doesn't post. This is the curl example of the request that they give on Share API doc.

curl -i --upload-file /Users/peter/Desktop/superneatimage.png --header "Authorization: Bearer redacted" 'https://api.linkedin.com/mediaUpload/C5522AQGTYER3k3ByHQ/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&m=AQJbrN86Zm265gAAAWemyz2pxPSgONtBiZdchrgG872QltnfYjnMdb2j3A&app=1953784&sync=0&v=beta&ut=2H-IhpbfXrRow1'

Can you tell me what is wrong with my java equivalent?

Edit: Forgot to say i even tried calling curl from java, the same code i used in the terminal, and it still didn't work..

        Process p;
        try {
            p = Runtime.getRuntime().exec("curl -i --upload-file" + " " + pictureUrl + " " + "--header \"Authorization: Bearer " + myToken + "\" '" + uploadUrl + "'");
            p.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = "";
            String outputController = "";
            while ((line = reader.readLine()) != null) {
                outputController = outputController + '\n' + line;
            }
            System.out.println("out: ");
            System.out.println(outputController);
            return true;
        } catch (IOException | InterruptedException ex) {
            return false;
        }

Output returned an empty String.

Edit2: Another funny thing, when i execute the main request, in which i send the text, and media urns that i get after submitting images, i get 201 again, like it's successful, and in the response i even get the post id. Then i try to use the another api endpoint and pull that post using the id i got from the response, and i get all the data, like the post is posted. It even says in the json that i get that lifecycle is PUBLISHED and the status of the medias is READY. Only thing that's different from the json an image post that is on linkedin is that the media object have thumbnails, and in this case they don't, it's just an empty json array.

AlexV
  • 116
  • 8

4 Answers4

2

I found curl to C# converter https://curl.olsh.me/ below is code snippet is generated:



    using (var httpClient = new HttpClient())
    {
        using (var request = new HttpRequestMessage(new HttpMethod("PUT"), "https://api.linkedin.com/mediaUpload/C5522AQGTYER3k3ByHQ/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&m=AQJbrN86Zm265gAAAWemyz2pxPSgONtBiZdchrgG872QltnfYjnMdb2j3A&app=1953784&sync=0&v=beta&ut=2H-IhpbfXrRow1"))
        {
            request.Headers.TryAddWithoutValidation("Authorization", "Bearer redacted"); 

            request.Content = new ByteArrayContent(File.ReadAllBytes("/test.png")); 

            var response = await httpClient.SendAsync(request);
        }
    }

Wilson
  • 21
  • 3
1

Ok I've solved it, if anyone encounters the same problem, this is what i did wrong. In the request i added a multipart to request body, this is wrong, you just go RAW. So instead of

    File file = new File(pictureUrl);
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    builder.addBinaryBody("upload-file", file);
    request.setEntity(builder.build());

you just put

request.setEntity(new FileEntity(new File(pictureUrl), ContentType.create(picture.getContentType())));

and then everything goes on ok.

AlexV
  • 116
  • 8
  • what about the next step for this (share the post), it requires user id in request body but I can't get it in back-end (error 500) – Ahmed E. Eldeeb Apr 01 '19 at 16:00
  • If you're using the https://api.linkedin.com/v2/ugcPosts you don't require user id, you need your urn in the author field. URN is constructed like this: "urn:{namespace}:{entityType}:{id}". Namespace is always "li", entity type can be "organization/person/sponsoredAccount", and the id you get when you call https://api.linkedin.com/v2/me. I use my page to share posts so my urn is urn:li:organization:myCustomId – AlexV Apr 03 '19 at 10:06
0

Not familiar with Java, but I had the same problem using Ruby and I fixed it by adding the MIME type of the image I was uploading as the Content-Type in the request headers. So in your specific case it would be:

request.addHeader("Content-Type", "image/png");

Also take a look at my solution using Ruby's RestClient and Minimagick: https://stackoverflow.com/a/54902863/7844946

Ervin Kalemi
  • 569
  • 4
  • 14
  • By the way, what's the status of your asset? Is it "CLIENT_ERROR"? – Ervin Kalemi Feb 28 '19 at 19:12
  • I've tried changing the content type to the image mime type, but still no luck. Where do you see the status of the asset? – AlexV Feb 28 '19 at 19:18
  • You can make a GET request to https://api.linkedin.com/v2/assets//{ASSET_ID}. Asset id is returned from the registerUpload call. P.S. Asset id, not the urn, i.e. GET https://api.linkedin.com/v2/assets/C4D22AQHzpy09pIC8tw – Ervin Kalemi Feb 28 '19 at 19:24
  • https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/vector-asset-api#check-status-of-upload – Ervin Kalemi Feb 28 '19 at 19:26
  • Yeah... I get "CLIENT_ERROR" – AlexV Feb 28 '19 at 19:34
  • If the asset doesn't have the status AVAILABLE, the post won't show up on LinkedIn. Most likely the file is not being sent properly. I wish I still remembered Java. I'm surprised the curl call within Java didn't work. Was the pictureUrl an absolute path? – Ervin Kalemi Feb 28 '19 at 19:40
  • Yeah, pictureUrl is an absolute path. If i try the same string that i used in java curl call in the terminal, it works. Yeah i guess the request isn't being sent properly, let's hope someone can correct my java. Thanks for trying anyway. – AlexV Feb 28 '19 at 19:44
  • I've tried using curl from java again, and checked the asset status, now the status is stuck on "WAITING_UPLOAD" for 10 minutes. – AlexV Feb 28 '19 at 20:04
  • WAITING_UPLOAD means that you haven't made the call to upload the image yet. As soon as you make the call, the status changes to PROCESSING and then to either AVAILABLE or CLIENT_ERROR depending on the request. – Ervin Kalemi Feb 28 '19 at 20:26
  • Ah, alright, so that means I'm not calling curl from java correctly either, haha. – AlexV Feb 28 '19 at 20:29
  • You're not calling it at all haha – Ervin Kalemi Feb 28 '19 at 20:31
  • I am getting the same issue in php. CLIEN_ERROR in assets. Anyone please help. – Sachin Jun 20 '19 at 08:10
  • This did not work for me .. adding request header `content-type: multipart/form-data` for file uploads work for me – Sathish Dec 02 '20 at 11:09
0

I was writing with kotlin and after struggling with the same problem for a long time I managed to fix it, for those struggling with the similar problem, I'll leave my sample codes below. For the visual you need to provide a direct URI path, also pay attention to the header structure.

Here are the codes.

var file = File(ImageURI)
    val urls = URL(url)
    var connection: HttpsURLConnection = urls.openConnection() as HttpsURLConnection
    connection.setRequestProperty("Authorization","Bearer " + accesToken)
    connection.setRequestProperty("Content-Type", "image/png")
    connection.setRequestProperty("cache-control", "no-cache")
    connection.setRequestProperty("X-Restli-Protocol-Version", "2.0.0")
    connection.requestMethod = "POST"
    connection.doOutput = true
    connection.doInput = true

    var request = DataOutputStream(connection.outputStream)
    request.write(file.readBytes())
    request.flush()

    println("Response: "+connection.responseCode)
Yavo
  • 43
  • 5