Api-platform: Best practice to include a download option in subresource?

Created on 28 May 2019  路  3Comments  路  Source: api-platform/api-platform

Hi

I am trying to create a custom download operation to a subresource collection and I am still struggling to understand the proper implementation. I have checked the documentation and some github support issue examples but still could not find any proper clear examples.

Here is the simplified version of my current implementation

<?php

use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiSubresource;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\DateFilter;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity(repositoryClass="AccountRepository")
 * @ORM\Table(name="accounts")
 *
 * @ApiResource(
 *     attributes={"access_control"="is_granted('ROLE_USER')"},
 *     itemOperations={
 *          "get_transactions_download"={
 *              "method"="GET",
 *              "path"="/accounts/{id}/download-transactions.{_format}",
 *              "controller"=DownloadTransactionsAction::class
 *         }
 *     },
 *     normalizationContext={
 *          "groups"={"read"}
 *     }
 * )
 */
class Account
{
    /**
     * @ORM\OneToMany(targetEntity="Transaction", fetch="EXTRA_LAZY", mappedBy="account")
     * @ApiSubresource(maxDepth=1)
     */
    private $transactions;
}



/**
 * @ORM\Entity(repositoryClass="TransactionRepository")
 * @ORM\Table(name="account_transactions")
 *
 * @ApiResource(
 *     subresourceOperations={
 *          "api_accounts_transactions_get_subresource"={
 *              "method"="GET",
 *              "normalization_context"={"groups"={"read"}}
 *          }
 *     }
 * )
 * @ApiFilter(DateFilter::class, properties={"transactionDate"})
 */
class Transaction
{
    /**
     * @ORM\ManyToOne(targetEntity="Account", inversedBy="transactions", cascade={"remove"})
     * @ORM\JoinColumn(name="account", nullable=false, onDelete="CASCADE")
     */
    private $account;

    /**
     * @ORM\Column(name="transaction_date", type="datetime")
     * @Groups({"read"})
     */
    private $transactionDate;
}

Above implementation works fine without any problem and transactions can be requested from '/api/accounts/{id}/transactions.{_format}' url. So I am trying to implement a download feature to allow users to download the same collection as a csv file. (remove limit and pagination without removing the filtering options)

Current workaround
I am using a custom controller on the main resource entity and it seems more of a hack and I am missing the date filtering features of transaction resource.

Any help would be greatly appreciated!

question

All 3 comments

remove limit and pagination without removing the filtering options

There is no support for per-operation filters.

But to force a download, just add a custom listener that adds the correct HTTP header on the Response, depending on the operation name.

Or just use a download query parameter? Saves you a lot of trouble.

Hi @teohhanhui , Thanks for the response and support :)! Interesting... I never thought about additional query parameters option. So we force a csv download instead of json without result limits.

json:
/api/accounts/{id}/transactions.{_format}?page=2&transactionDate[before]=2018-04-04

csv download:
/api/accounts/{id}/transactions.{_format}?transactionDate[before]=2018-04-04&download=1

Do you think it's possible? if it's possible at which point we modify the response?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maximilienGilet picture maximilienGilet  路  3Comments

kswzr picture kswzr  路  3Comments

irmantas picture irmantas  路  3Comments

sverraest picture sverraest  路  3Comments

john-dufrene-dev picture john-dufrene-dev  路  3Comments