How to get uploaded image url using the Discourse API?

If I use this api:

curl -X POST -F username="john" -F type="image" -F file="@image.png" -F synchronous="true" "http://localhost:3000/uploads?api_key=SOMETHING&api_username=SOMEONE"

I just can get a response with “{"success":"OK"}”. But I want to get the image url .

I see the topic to solve how to get image url:

https://meta.discourse.org/t/using-the-discourse-api-to-post-with-uploaded-files/29833/23

new api:

curl -X POST -F type=composer -F client_id=1234b591bb4848dd899b6e6ee0feaff9 -F 'files[]=@12HourDate.kmmacros' 'http://forum.keyboardmaestro.com/uploads.json?api_key=APIKEY&synchronous=1'

I can’t understand how to get the client_id? If I add the param “synchronous=1” in url. No return value!

Nobody can help me ?
:sob::sob::sob:

client_id is assigned randomly, but you should not need it if synchronous 1 is enabled.

1 Like

So I can write client_id randomly?
But incorrectly when I write the client_id randomly.
why…

client_id is used for asynchronous uploads, we notify that client via the message bus that an upload was processed once it is process, which is why it should not matter if synchronous is enabled. There is no messaging.

2 Likes

Thank you.:stuck_out_tongue:

curl -X POST -F username="john" -F type="image" -F file="@image.png" -F synchronous="true" "http://localhost:3000/uploads?api_key=SOMETHING&api_username=SOMEONE"

I write a php fucntion to test this upload api.

public function upload_file($user) {
  $url = 'http://hostname/uploads?api_key=api_key&api_username=api_username';
  $poststr = http_build_query(array('username' => $user, 'type' => 'image', 'file' => '/uploads/file/filename', 'synchronous' => 'true');
  $data = _curl($url, $poststr));  // _curl() : a custom function 
  return $data;
}

$data is empty. Why is it empty? It’s not supposed to return a url.

if I remove a parammeter : synchronous, it will return the response of “{“success”:“OK”}”.

1 Like

Thanks.
But I want to put the photos uploaded to the discourse server

This may just be a really weird PHP API, but where do you shuffle the actual file data to the server? I don’t know your _curl(), but it looks like it just gets a URL and some query parameters.

function _curl($url,$poststr='',$httpheader=array(),$usecookie=false){
        $ch = curl_init();
        $SSL = substr($url, 0, 8) == "https://" ? true : false;
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        if ( $SSL ) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
        }
        if( $poststr!='' ){
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $poststr);
        }
        if( $httpheader ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
        }
        if( $usecookie ){
        	$cookie_jar = APPPATH.'cache/logs/curl_cookie_'.md5($url).'.log';
        	curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
        }
        
        $data = curl_exec($ch);
        curl_close($ch);
        return  $data;
    }

Curl is a tool and libcurl is a library for transferring data with URL syntax. It not just gets a URL and some query parameters
Before, I can use this curl function to submit data to discourse server when I create a new topic.

Look down a successful example to create a new topic using the api.

public function create_topic($params) {
        $url = 'http://hostname/posts?api_key=api_key&api_username=api_username';
        $poststr = http_build_query(array('raw' => $params['raw'], 'title' => $params['title'], 'category' => $params['category']));
        $result = array('success' => false, 'msg' => 'failed');
        if(($data=_curl($url, $poststr)) && ($json = json_decode($data, true))) {
            if( !empty($json)) {
                if(isset($json['errors'])) {
                    $result['msg'] = $json['errors'][0];
                }
                else {
                    $result['success'] = true;
                }
            }
        }
        return $result;
    }

Thank you.:stuck_out_tongue:

1 Like

Oh, I know what curl is. I’m just pointing out that I don’t see where you’re sending the actual contents of the file you are supposedly uploading to Discourse. Without contents I don’t expect Discourse to be happy with the upload, so I wouldn’t expect a successful result.

1 Like

Get rid of the function http_build_query, we can upload image successfully!

public function upload_file($user) {
  $url = 'http://hostname/uploads?api_key=api_key&api_username=api_username';
  $poststr = http_build_query(array('username' => $user, 'type' => 'image', 'file' => '/uploads/file/filename', 'synchronous' => 'true'));    // get rid of the function http_build_query, we can upload image successfully!
  $data = _curl($url, $poststr));  // _curl() : a custom function 
  return $data;
}

After change

  $poststr = array('username' => $user, 'type' => 'image', 'file' => '/uploads/file/filename', 'synchronous' => 'true');    // get rid of the function http_build_query, we can upload image successfully!

In summary, when we submit data to discourse server using curl, we may use three method to post parameters. You should try more methods when you encounter problems.

one: json
two: http_query_query
three: array

There may be more.:slightly_smiling:

1 Like

hi all,

i am trying to upload image using ajax, and getting 400 bad request.
but there is no message so i can see what is going on.
Have my csrf token, and also logged in but still nothing.

code looks something like this

 $.ajax({
                    headers: { 'X-CSRF-Token': data.csrf },
                    url: '/forum/uploads.json?synchronous=1',
                    type: 'POST',
                    data: formData,
                    cache: false,
                    contentType: false,
                    processData: false,
                    success: function (xhr) {
                   
                    },
                });

i guess it is maybe because i am using formData, if it is can you please tell me in which format i need to send image?

Thanks

1 Like

I’m not really sure what all you will need to do to get it to work via ajax (api key, csrf, cors, etc?), but here is how you can get an upload to work via the api (this is for an avatar upload, but it is the same endpoint, you probably just need to change the type):

i actually want to first upload image, and than with that image to make a post.
i made posts without api_key and api_username since i have csrf token and cookie,
so i guess i don’t need for this upload too.

this is my call for creating post :

                headers: { 'X-CSRF-Token': data.csrf },
                data: JSON.stringify({
                    raw: this.get('comment'),
                    topic_id: this.get('topicId')
                }),
                contentType: 'application/json',

so as you can see, without api_key and api_username.

but can you tell me more about this type, what should i put if i want to upload image before post?
and user_id, i don’t have user id, and i didn’t use it for any of the for any calls until now.

so only cookie and csrf

sorry the user_id is only if the type is avatar.

I’m pretty sure you will need a post_id though if you are uploading it to a post.

I’m not sure off the top of my head, but you can:

The current issue you will run into though is that we don’t return the upload_id:

exactly, that’s where i am stuck right now :slight_smile:

so, i made a call, uploaded picture, but there is no url to the picture in the response, only success : OK.
is there a way to get url to the image in the response?

thanks

i saw here: https://meta.discourse.org/t/using-the-discourse-api-to-post-with-uploaded-files/29833/23
that there is a way to get the link in response,
but i am using this synchronous param set to 1 and still nothing but success : OK

this was more a question. So is there a clean a way, proposed by discourse to upload image via API, and retrieve image in response?

Or maybe to make upload and then request again for image link?

Thanks!

One of the issues you are having has to do with the type parameter being set to ‘POST’ in all caps. It needs to be a value that complies with this rule:

https://github.com/discourse/discourse/blob/887e9af84ffbfdfe1925164947af9892f9f2bbec/app/controllers/uploads_controller.rb#L8

Besides being used for determining if you are uploading an “avatar”, I’m not totally sure yet what all type is used for. So I would just set it to some all lowercase string like “upload”.

Here is an example file upload request and response API call:

2 Likes

i did everything u said :

    formData.append('type', 'upload');
    formData.append('post_id', '6640');
    formData.append('files', imageFile);
    formData.append('synchronous', true);


 $.ajax({
                headers: { 'X-CSRF-Token': data.csrf },
                url: '/forum/uploads',
                type: 'post',
                data: formData,
                async: false,
                cache: false,
                contentType: false,
                processData: false,
                success: function (status, xhr, msg) {
                    if (status) {
                     
                    }
                },

                error: function (status) {
                    if (status) {
                  
                    }
                }
            });

and still nothing but success : OK.

do you have maybe any other idea, what it can be?