@@ -479,167 +479,3 @@ resources:
479479API Platform will find the operation matching this ` itemUriTemplate ` and use it to generate the IRI.
480480
481481If this option is not set, the first ` Get ` operation is used to generate the IRI.
482-
483- ## Expose a Model Without Any Routes
484-
485- Sometimes, you may want to expose a model, but want it to be used through subrequests only, and never through item or collection operations.
486- Because the OpenAPI standard requires at least one route to be exposed to make your models consumable, let's see how you can manage this kind
487- of issue.
488-
489- Let's say you have the following entities in your project:
490-
491- ``` php
492- <?php
493- // api/src/Entity/Place.php
494- namespace App\Entity;
495-
496- use Doctrine\ORM\Mapping as ORM;
497-
498- #[ORM\Entity]
499- class Place
500- {
501- #[ORM\Id, ORM\Column, ORM\GeneratedValue]
502- private ?int $id = null;
503-
504- #[ORM\Column]
505- private string $name = '';
506-
507- #[ORM\Column(type: 'float')]
508- private float $latitude = 0;
509-
510- #[ORM\Column(type: 'float')]
511- private float $longitude = 0;
512-
513- // ...
514- }
515- ```
516-
517- ``` php
518- <?php
519- // api/src/Entity/Weather.php
520- namespace App\Entity;
521-
522- class Weather
523- {
524- private float $temperature;
525-
526- private float $pressure;
527-
528- // ...
529- }
530- ```
531-
532- We don't save the ` Weather ` entity in the database, since we want to return the weather in real time when it is queried.
533- Because we want to get the weather for a known place, it is more reasonable to query it through a subresource of the ` Place ` entity, so let's do this:
534-
535- ``` php
536- <?php
537- // api/src/Entity/Place.php
538- namespace App\Entity;
539-
540- use ApiPlatform\Metadata\Get;
541- use ApiPlatform\Metadata\Put;
542- use ApiPlatform\Metadata\Delete;
543- use ApiPlatform\Metadata\GetCollection;
544- use ApiPlatform\Metadata\Post;
545- use ApiPlatform\Metadata\ApiResource;
546- use App\Controller\GetWeather;
547- use Doctrine\ORM\Mapping as ORM;
548-
549- #[ApiResource(
550- operations: [
551- new Get(),
552- new Put(),
553- new Delete(),
554- new Get(name: 'weather', uriTemplate: '/places/{id}/weather', controller: GetWeather::class),
555- new GetCollection(),
556- new Post(),
557- ]
558- )]
559- #[ORM\Entity]
560- class Place
561- {
562- // ...
563- ```
564-
565- The ` GetWeather ` controller fetches the weather for the given city and returns an instance of the ` Weather ` entity.
566- This implies that API Platform has to know about this entity, so we will need to make it an API resource too:
567-
568- ``` php
569- <?php
570- // api/src/Entity/Weather.php
571- namespace App\Entity;
572-
573- use ApiPlatform\Metadata\ApiResource;
574-
575- #[ApiResource]
576- class Weather
577- {
578- // ...
579- ```
580-
581- This will expose the ` Weather ` model, but also all the default CRUD routes: ` GET ` , ` PATCH ` , ` DELETE ` and ` POST ` , which is nonsense in our context.
582- Since we are required to expose at least one route, let's expose just one:
583-
584- ``` php
585- <?php
586- // api/src/Entity/Weather.php
587- namespace App\Entity;
588-
589- use ApiPlatform\Metadata\ApiResource;
590- use ApiPlatform\Metadata\Get;
591-
592- #[ApiResource(operations: [
593- new Get(controller: SomeRandomController::class)
594- ])]
595- class Weather
596- {
597- // ...
598- }
599- ```
600-
601- This way, we expose a route that will do… nothing. Note that the controller does not even need to exist.
602-
603- It's almost done, we have just one final issue: our fake item operation is visible in the API docs.
604- To remove it, we will need to [ decorate the Swagger documentation] ( openapi.md#overriding-the-openapi-specification ) .
605- Then, remove the route from the decorator:
606-
607- ``` php
608- <?php
609- // src/OpenApi/OpenApiFactory.php
610- namespace App\OpenApi;
611-
612- use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
613- use ApiPlatform\OpenApi\OpenApi;
614- use ApiPlatform\OpenApi\Model;
615-
616- final class OpenApiFactory implements OpenApiFactoryInterface
617- {
618- private $decorated;
619-
620- public function __construct(OpenApiFactoryInterface $decorated)
621- {
622- $this->decorated = $decorated;
623- }
624-
625- public function __invoke(array $context = []): OpenApi
626- {
627- $openApi = $this->decorated->__invoke($context);
628-
629- $paths = $openApi->getPaths()->getPaths();
630-
631- $filteredPaths = new Model\Paths();
632- foreach ($paths as $path => $pathItem) {
633- // If a prefix is configured on API Platform's routes, it must appear here.
634- if ($path === '/weathers/{id}') {
635- continue;
636- }
637- $filteredPaths->addPath($path, $pathItem);
638- }
639-
640- return $openApi->withPaths($filteredPaths);
641- }
642- }
643- ```
644-
645- That's it: your route is gone!
0 commit comments