Download CSV from shopware 6 administration

Viewed 65

I want to implement a CSV export from Shopware 6 admin. I have a button, want to open a new window and get a CSV file.

I implemented a controller:

/**
 * @Route(
 *     "/api/winkelwagen/export/csv/{id}",
 *     methods={"GET"},
 *     defaults={"auth_required"=true, "_routeScope"={"api"}}
 * )
 */
public function export(string $id, Context $context, Request $request): Response
{
    /** @var PromotionEntity $promo */
    $response->setContent('csv file');

    return $response;
}

But to call this controller, you need to be logged in which totally make sense.

My button in the administration currently opens a new window and opens the page:

window.open('http://www.fabian-blechschmidt.de', '_blank');

Which of course doesn't work with the api url, because you needs to be authenticated.

So my question is: How do I implement this authentication and get a CSV file in the backend? :-)

Maybe my approach is totally broken - happy to get a better idea!

3 Answers

You can use the built in http client and set the bearer token for authentication:

const initContainer = Shopware.Application.getContainer('init');
initContainer.httpClient.get(
    `winkelwagen/export/csv/${id}`,
    {
        headers: {
            Accept: 'application/vnd.api+json',
            Authorization: `Bearer ${Shopware.Service('loginService').getToken()}`,
            'Content-Type': 'application/json',
        },
    },
);

Change the headers according to your needs.

To extend on the answer from dneustadt, the code snippet below also actually downloads the csv as a file by loading the data into a data url and clicking it virtually.

const initContainer = Shopware.Application.getContainer('init');
initContainer.httpClient.get(
    `winkelwagen/export/csv/${id}`,
    {
        headers: {
            Accept: 'application/vnd.api+json',
            Authorization: `Bearer ${Shopware.Service('loginService').getToken()}`,
            'Content-Type': 'application/json',
        },
    },
).then((response) => {
    if (response.data) {
        const filename = response.headers['content-disposition'].split('filename=')[1];
        const link = document.createElement('a');
        link.href = URL.createObjectURL(response.data);
        link.download = filename;
        link.dispatchEvent(new MouseEvent('click'));
        link.parentNode.removeChild(link);
    }
});

dneustadt is a great start! But Rune Laenen's answer is gold!

But I think due to the fact, that I don't return JSON but a CSV file, I needed to change a few things.

  • For some reason the filename contained " as prefix and suffix - we cut these.
  • The response.data is neither a file nor a Blob, which is needed for URL.createObjectURL - no problem, we just make one.
  • and the link doesn't seem to be attached to document, so we make sure no error is thrown
     if (response.data) {
        let filename = response.headers['content-disposition'].split('filename=')[1];
        filename = filename.substring(1, filename.length - 1);
        const link = document.createElement('a');
        link.href = URL.createObjectURL(new Blob([response.data], {type: response.headers['content-type']}));
        link.download = filename;
        link.dispatchEvent(new MouseEvent('click'));
        try {
            link.parentNode.removeChild(link);
        } catch (e) {
            // do nothing
        }
    }
Related