Extend ApiResource by a custom route with a different output format

Viewed 97

Banging my head about options and what's a fine way how to achieve it.

Using Api-Platform per default. I have an ApiResource Invoice (Doctrine ORM Entity) which provides the common routes for

  • GET invoices
  • POST invoices
  • GET invoices/{id}
  • DELETE invoices/{id}

etc. They create, list, delete etc. the Invoice Entity.

Now I want to have an additional route called

  • GET invoices/{id}/documents

which needs an Invoice object as an input but only provides application/pdf as an output.

The result is produced by a service which requires the Invoice object to produce the Invoice PDF document.

What I tried so far is to annotate my Invoice Entity

#[ApiResource(itemOperations: [
'get',
'put',
'patch',
'delete',
'get_document' => [
    'method' => 'GET',
    'path' => '/invoices/{id}/document',
    'controller' => DocumentController::class,
    'output_formats' => ['application/pdf']
],
])]

and creating a DocumentController class like

#[AsController]
class DocumentController extends AbstractController
{
private InvoiceDocumentService $documentService;

public function __construct(InvoiceDocumentService $invoiceDocumentService)
{
    $this->documentService = $invoiceDocumentService;
}

public function __invoke(Invoice $data): string
{
    return $this->documentService->createDocumentForInvoice($data);
}
}

But now it seems that the application/pdf MIME is not supported and I need to create/register my own Encoder for it etc...

I assume I will have to decorate OpenApi as well to document it etc.

Before I continue on this journey... am I on the right track at all?

Or is there another way to achieve my goal?

1 Answers

I don't know what is the easiest way to display a PDF route to the openAPi view, but in my opinion, your use case looks more like :

  • an Invoice schema and its url property
  • or a MediaObject schema and its contentUrl property.

So just add a method to your Invoice indicating the PDF URL:

#[Groups(["read:invoice"])]
public function getUrl(): string
{
    return "/invoices/{$this->id}/document";
}

then move your InvoiceDocumentService to a regular Symfony controller.

PS: don't forget to add a securtity system to avoid anyone to fetch the invoice or any customer, by iterating on the ID for example.

Related