rhand's avatar
Level 6

Axios.get then Axios.post to store images from api on server

How can I first use an axios get request to load the image from the api and then store it on the server with a post request? Can this be done in one function call or should it be done and two? Do I need a temporary storage location before I store it on the server?

0 likes
13 replies
click's avatar

Not a direct answer on your question but: are the API calls on the same server? Can't you create one api where you can say: download this, upload it there? Or this not working for you?

1 like
rhand's avatar
Level 6

The API call is done on our server and files are loaded from Unsplash. So getting the files to display for selection is working. But now I need them to be saved on click. So I am trying to do something like

// save button function to be called
// should download from Unsplash using their download_location
// this works with get.axios 
// and then store on our server
// store part here is not working yet
saveSearchedUnsplashPhotoToServer : function(result) {
                var apiLink = result.links.download_location;
                const config = {
                    params: {
                        client_id: '1111',
                    }
                }
                axios
                    .get(apiLink, config)
                .then(
                    axios.post('/backend/upload-image/',  data: some-data).then(this.handleSuccessfulSave).catch(this.catch);
                
                )
                .catch(this.catch);
            },

So I need a step to perhaps download to a temporary folder and then to uploads folder.. But I am not sure yet how. The API call I use is fine, but the axios get call I use now combines local url and remote api url resulting in a 404 with

 saveSearchedUnsplashPhotoToServer : function(result) {
                axios.get('/backend/upload-image/' + result.links.download_location, { results: result.links.download_location } )
                .then(this.handleSuccessfulSave)
                .catch(this.catch);
            },

404 caused by get http://laravel.test/backend/upload-image/https://api.unsplash.com/photos/9FDKj-FrfA4/download url being created I need to get the file and have it stored in the proper uploads folder

click's avatar

I would create post request (that uses csrf tokens). And post the url as a parameter.

axios.post('/backend/upload-image', {
    source: result.links.download_location
})
.then(this.handleSuccessfulSave)
.catch(this.catch)

And make sure you only allow certain domain names to download from and certain file types. Otherwise anybody could upload any kind of files.

1 like
rhand's avatar
Level 6

Just the axios.post

axios.post('/backend/upload-image', {
    source: result.links.download_location
})
.then(this.handleSuccessfulSave)
.catch(this.catch)

does not work resulting in an error 500 Call to a member function isValid() on null and it refers to this line

 if ( !$request->file('file')->isValid() )

And that is probably because no file was downloaded. Seems I do need to get the axios.get and pipe it to the axios.post . Unless this has to do with CSRF..

This:

saveSearchedUnsplashPhotoToServer : function(result) {
                var apiLink = result.links.download_location;
                const config = {
                    params: {
                        client_id: '11111',
                        responseType: 'json',
                    }
                }
                axios
                    .get(apiLink, config)
                .then(
                axios.post('/editor/upload-image', {
                    source: result.links.download_location
                }))
                .then(this.handleSuccessfulSave)
                .catch(this.catch)
            },

resulted in the same error 500 FatalThrowableError Call to a member function isValid() on nul

And 'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content') also got a Cannot read property 'getAttribute' of null

And I doubt I needed it as I have

window.axios = require('axios');

window.axios.defaults.headers.common = {
    'X-CSRF-TOKEN': window.Laravel,
    'X-Requested-With': 'XMLHttpRequest'
};

in bootstrap.js

click's avatar

You do not have a file in your request if you only post an url. I assume that the source we are talking about is a public accessible url? If not, I didn't understood your problem at first. If it is a public accessible url you can download it on your server:

Simple example:

$sourcePath = $request->post('source');
$destinationPath = storage_path('path/to/your/path');

// @todo implement validation of the type of file you are going to download is safe. Is it from the correct domain, is it an actual image, etc. 

// download the remote file to your storage path
copy($sourcePath, $destinationPath);
1 like
rhand's avatar
Level 6

I load Unsplash data this way for search display in Vue for loop:

performSearch: function() {
                console.log(this.searchTerm);
                var link = 'https://api.unsplash.com/search/photos?query=';
                var apiLink = link + this.searchTerm;
                const config = {
                    params: {
                        client_id: '1111',
                    }
                }

                axios
                    .get(apiLink, config)
                    .then(response => {
                    this.results = response.data.results;
                    })
                    .catch(error => {
                    console.log(error);
                    });
            },

I can select these in preview with another loop:

<div class="selected-info-container col-md-3">
                                <div class="selected-info-header">
                                    selected image
                                </div>
                                <div style="width: 100%; height: 100%; overflow: hidden; padding-top: 10px;" v-for="(result, results) in results" :key="results.id" v-if="isActive[result.urls.small]">
                                    <div class="form-group row">
                                        <img :src="result.urls.thumb" />
                                    </div>
                                    <div class="form-group row">
                                        <button class="btn btn-primary pull-right" @click="saveSearchedUnsplashPhotoToServer(result)">save</button>
                                        <!-- <button class="btn btn-primary pull-right" @click="startCrop">crop</button> -->
                                    </div>
                                </div>

Post select I use save to store the image on our server.. Well I want to.

According to https://medium.com/unsplash/unsplash-api-guidelines-triggering-a-download-c39b24e99e02

result.links.download_location

should trigger a download so I am trying to use that. result.links.download_location converts to an image url for downloading via their API. A url of an image selected. But somehow that is not grabbed

click's avatar

Ok, I understand your problem now better with this information.

What is the response of the get request to the result.links.download_location? Reading the article you posted it looks like the download_location is not downloading any image:

Note that the download_location is an event endpoint, meaning that it’s not meant to be used for anything other than making a single GET request when a user has used the photo in some way similar to a download.

Cronix's avatar
if ( !$request->file('file')->isValid() )

Isn't it called source instead of file?

axios.post('/backend/upload-image', {
    source: result.links.download_location
})
rhand's avatar
Level 6

I get these headers:

Request URL: https://api.unsplash.com/photos/KEPISdOJhxk/download?client_id=11111&responseType=json
Request Method: GET
Status Code: 200 
Remote Address: 151.101.141.181:443
Referrer Policy: no-referrer-when-downgrade
accept-ranges: bytes
access-control-allow-credentials: true
access-control-allow-headers: *
access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS
access-control-allow-origin: http://laravel.test
access-control-expose-headers: Link, X-Total, X-Per-Page, X-RateLimit-Limit, X-RateLimit-Remaining
access-control-max-age: 1728000
access-control-request-method: *

or this response

{"url":"https://images.unsplash.com/photo-1519612535780-b5d7d96c36f3?ixlib=rb-0.3.5\u0026q=85\u0026fm=jpg\u0026crop=entropy\u0026cs=srgb\u0026s=42c89d2eae581ba0fe58dcd0ce90ab12"}

using

saveSearchedUnsplashPhotoToServer : function(result) {
                var apiLink = result.links.download_location;
                const config = {
                    params: {
                        client_id: '1111',
                        responseType: 'json',
                    }
                }
                axios
                    .get(apiLink, config)
                    console.log(result.links.download_location)
                //.then(this.handleSuccessfulSave)
                //.catch(this.catch);
            },

and console output was https://api.unsplash.com/photos/Mv9hjnEUHR4/download

rhand's avatar
Level 6

I did read in the blog post now

or to direct the user downloading the photo to (use the photo.urls.full for that instead). The download_location is not to be used to embed the photo (use the photo.urls.* properties instead) or to direct the user downloading the photo to (use the photo.urls.full for that instead).

So perhaps I need to trigger it for views in the modal and preview and even for downloads just so authors get that registered on Unsplash, but the real downloads need to be done with a different one photo.urls.full

click's avatar
click
Best Answer
Level 35

Ok I am not going to post all the code here but I would do it as follows:

  1. Do whatever you need to do with that API to get to the right image.
  2. Get a public URL from that API. It looks like you received one because https://images.unsplash.com/photo-1519612535780-b5d7d96c36f3?ixlib=rb-0.3.5\u0026q=85\u0026fm=jpg\u0026crop=entropy\u0026cs=srgb\u0026s=42c89d2eae581ba0fe58dcd0ce90ab12 is publicly available
  3. Send that url to your server backend with a post variable as explained in my earlier comment. Let your php server download and store it. And you should be done.
rhand's avatar
Level 6

Did some more trials. All error 500. I do not understand how I should add the data really. In the get requests I do. In the axios.post I don't. All these options below have failed. This as I do somehow load data in get request well, but not in post. Destination url is correct and for that route I do have a function.

It is just that no data is loaded. I added result to the function as a parameter as it allowed me to make the get request work. But for the post I need something else it seems..

saveSearchedUnsplashPhotoToServer : function(result) {
                axios.post('/backend/upload-image', {
                file: result.urls.full
                })
            }, 

saveSearchedUnsplashPhotoToServer : function(result) {
    axios.post('/backend/upload-image', {
    result: result.urls.full
    })
},

saveSearchedUnsplashPhotoToServer : function(result) {
    axios.post('/backend/upload-image', {
    results: result.urls.full
    })
}, 

saveSearchedUnsplashPhotoToServer : function(result) {
    axios.post('/backend/upload-image', {
    source: result.urls.full
    })
}, 

saveSearchedUnsplashPhotoToServer : function(result) {
    axios({
        method: 'post',
        url: '/backend/upload-image',
        client_id: '111',
        data: {results: result.urls.full}
        });
}, 

the get request

saveSearchedUnsplashPhotoToServer : function(result) {
                axios.get(result.urls.full, { results: result.urls.full } )
                 .then(this.handleSuccessfulSave)
                 .catch(this.catch);
             }, // 204 and 200 status

worked.

I am thinking that perhaps I will need a new route / controller or method for this

Will leave this thread for a while.

PS Clicked solved by accident. Will move solved to answer that solves it again later on.

rhand's avatar
Level 6

Get requests work based on help here.. So will close this thread. Just need help with server side controller for which I opened another thread.

Please or to participate in this conversation.