### Install API Platform Admin Source: https://api-platform.com/docs/v3.4/admin/getting-started Command to install the @api-platform/admin library. ```bash npm install @api-platform/admin ``` -------------------------------- ### Install Schema Generator with Composer Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started Installs the Schema Generator independently using Composer. ```bash composer require --dev api-platform/schema-generator ``` -------------------------------- ### YAML Resource Configuration Source: https://api-platform.com/docs/v3.4/core/getting-started Example of configuring resources using YAML. ```yaml resources: App\Entity\Product: ~ App\Entity\Offer: shortName: 'Offer' # optional description: 'An offer from my shop' # optional types: ['https://schema.org/Offer'] # optional paginationItemsPerPage: 25 # optional ``` -------------------------------- ### XML Resource Configuration Source: https://api-platform.com/docs/v3.4/core/getting-started Example of configuring resources using XML. ```xml description="An offer from my shop" > https://schema.org/Offer ``` -------------------------------- ### Install GraphQL dependencies Source: https://api-platform.com/docs/v3.4/distribution Command to install graphql-php and clear the cache. ```bash docker compose exec php sh -c ' composer require webonyx/graphql-php bin/console cache:clear ' ``` -------------------------------- ### Install Schema Generator via Docker Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started Installs the Schema Generator as a development dependency and invokes it through Docker. ```bash docker compose exec php \ vendor/bin/schema ``` -------------------------------- ### Initialize HydraAdmin Source: https://api-platform.com/docs/v3.4/admin/getting-started Example of replacing the content of src/App.js to initialize HydraAdmin with an API entrypoint. ```jsx import { HydraAdmin } from "@api-platform/admin"; // Replace with your own API entrypoint // For instance if https://example.com/api/books is the path to the collection of book resources, then the entrypoint is https://example.com/api export default () => ( ); ``` -------------------------------- ### Book Resource JSON Source: https://api-platform.com/docs/v3.4 Example JSON for a new book resource. ```json { "description": "This book is designed for PHP developers and architects who want to modernize their skills through better understanding of Persistence and ORM.", "author": "Kévin Dunglas", "publicationDate": "2013-12-01" } ``` -------------------------------- ### Install API Platform standalone bundle Source: https://api-platform.com/docs/v3.4/core/getting-started Use Composer to install the standalone API Platform bundle in an existing Symfony Flex project. ```bash composer require api ``` -------------------------------- ### Install API Platform's server component Source: https://api-platform.com/docs/v3.4/distribution Command to install the API Platform server component using Symfony composer. ```bash symfony composer require api ``` -------------------------------- ### Run Schema Generator with Configuration Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started Command to run the schema generator with a configuration file. ```bash vendor/bin/schema generate api/src/ api/config/schema.yaml -vv ``` -------------------------------- ### Start the built-in PHP server Source: https://api-platform.com/docs/v3.4/distribution Command to start the built-in PHP server. ```bash symfony serve ``` -------------------------------- ### Generate Code for Specific Resource Source: https://api-platform.com/docs/v3.4/distribution Example of generating client code for a specific resource, such as 'books'. ```bash pnpm create @api-platform/client --resource books ``` -------------------------------- ### Create React App Source: https://api-platform.com/docs/v3.4/admin/getting-started Command to create a new React application if one does not exist. ```bash npm init react-app my-admin cd my-admin ``` -------------------------------- ### Enter the project directory Source: https://api-platform.com/docs/v3.4 This command navigates into the newly created 'bookshop-api' project directory. ```bash cd bookshop-api ``` -------------------------------- ### Cardinality Extraction Usage Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started Command to run the Cardinality Extractor tool. ```bash vendor/bin/schema extract-cardinalities ``` -------------------------------- ### Enter the project directory Source: https://api-platform.com/docs/v3.4/distribution Command to navigate into the newly created project directory. ```bash cd bookshop-api ``` -------------------------------- ### Create Review Resource Source: https://api-platform.com/docs/v3.4/distribution Example JSON payload for creating a new review for a book. ```json { "book": "/books/1", "rating": 5, "body": "Interesting book!", "author": "Kévin", "publicationDate": "September 21, 2016" } ``` -------------------------------- ### Product Entity Source: https://api-platform.com/docs/v3.4/core/getting-started Example of an entity mapped using attributes, which will be exposed through a REST API. ```php offers = new ArrayCollection(); // Initialize $offers as a Doctrine collection } public function getId(): ?int { return $this->id; } // Adding both an adder and a remover as well as updating the reverse relation is mandatory // if you want Doctrine to automatically update and persist (thanks to the "cascade" option) the related entity public function addOffer(Offer $offer): void { $offer->product = $this; $this->offers->add($offer); } public function removeOffer(Offer $offer): void { $offer->product = null; $this->offers->removeElement($offer); } // ... } ``` -------------------------------- ### Create the database and schema Source: https://api-platform.com/docs/v3.4 These commands create the database and its schema using the Symfony console. ```bash symfony console doctrine:database:create symfony console doctrine:schema:create ``` -------------------------------- ### GraphQL query for books and reviews Source: https://api-platform.com/docs/v3.4/distribution Example GraphQL query to retrieve book data including titles and associated reviews. ```graphql { books { totalCount edges { node { id title reviews { totalCount edges { node { author rating } } } } } } } ``` -------------------------------- ### GraphQL mutation to create a greeting Source: https://api-platform.com/docs/v3.4/distribution Example GraphQL mutation to create a greeting. ```graphql mutation { createGreeting(input: {name: "Test2"}) { greeting { id name } } } ``` -------------------------------- ### Offer Entity Source: https://api-platform.com/docs/v3.4/core/getting-started Example of an Offer entity mapped using attributes, which will be exposed through a REST API. ```php id; } } ``` -------------------------------- ### Install API Platform's server component Source: https://api-platform.com/docs/v3.4 This command installs the API Platform server component into the Symfony skeleton using the Symfony composer. ```bash symfony composer require api ``` -------------------------------- ### POST request body for adding a book Source: https://api-platform.com/docs/v3.4/distribution Example JSON body to add a book to the API. ```json { "isbn": "2815840053", "description": "Hello", "author": "Me", "publicationDate": "today" } ``` -------------------------------- ### Start the built-in PHP server Source: https://api-platform.com/docs/v3.4 This command starts the built-in PHP server provided by the Symfony CLI. ```bash symfony serve ``` -------------------------------- ### Example POST Request Body for Book Resource Source: https://api-platform.com/docs/v3.4/distribution Example JSON document to be sent as a request body for the POST operation of the Book resource type in Swagger UI. ```json { "isbn": "9781782164104", "title": "Persistence in PHP with the Doctrine ORM", ``` -------------------------------- ### Create a new Symfony project Source: https://api-platform.com/docs/v3.4/distribution Command to create a new Symfony project. ```bash symfony new bookshop-api ``` -------------------------------- ### Follow Docker Logs Source: https://api-platform.com/docs/v3.4/distribution Follows the logs of the Docker containers in real-time. ```bash docker compose logs -f ``` -------------------------------- ### Controller Example Source: https://api-platform.com/docs/v3.4/core/controllers This example shows how to define a controller with routes for GET and POST requests. ```PHP new Get(), new Post( name: 'publication', uriTemplate: '/books/{id}/publication', controller: CreateBookPublication::class ) ]) class Book { // ... } ``` -------------------------------- ### Start Docker Compose Source: https://api-platform.com/docs/v3.4/distribution Starts all services defined in the Docker Compose file in detached mode, waiting for services to be ready. ```bash docker compose up --wait ``` -------------------------------- ### Run Schema Generator with Docker and Configuration Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started Command to run the schema generator using Docker Compose with a configuration file. ```bash docker compose exec php \ vendor/bin/schema generate src/ config/schema.yaml -vv ``` -------------------------------- ### API Platform Configuration for YAML/XML Source: https://api-platform.com/docs/v3.4/core/getting-started Configuration in `api_platform.yaml` to load YAML or XML resource files. ```yaml # api/config/packages/api_platform.yaml api_platform: mapping: paths: - '%kernel.project_dir%/src/Entity' # default configuration for attributes - '%kernel.project_dir%/config/api_platform' # yaml or xml directory configuration ``` -------------------------------- ### Schema Configuration for OpenAPI Generation Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started A YAML configuration file specifying the path to an OpenAPI documentation file. ```yaml # api/config/schema.yaml openApi: file: '../openapi.yaml' ``` -------------------------------- ### Create database and schema Source: https://api-platform.com/docs/v3.4/distribution Commands to create the database and its schema using Symfony console. ```bash symfony console doctrine:database:create symfony console doctrine:schema:create ``` -------------------------------- ### Schema Configuration for Enum Generation Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started A YAML configuration file for generating an enum class. ```yaml types: OfferItemCondition: # The generator will automatically guess that OfferItemCondition is subclass of Enum properties: {} # Remove all properties of the parent class ``` -------------------------------- ### Generate Database Migrations and Apply Source: https://api-platform.com/docs/v3.4/distribution Commands to generate a new database migration and apply it using Doctrine Migrations. ```bash docker compose exec php \ bin/console doctrine:migrations:diff docker compose exec php \ bin/console doctrine:migrations:migrate ``` -------------------------------- ### Create a new Symfony project Source: https://api-platform.com/docs/v3.4 This command creates a new Symfony project named 'bookshop-api'. ```bash symfony new bookshop-api ``` -------------------------------- ### Book Entity with Doctrine ORM Attributes Source: https://api-platform.com/docs/v3.4/distribution Example of a Book entity mapped to database tables using Doctrine ORM attributes. ```php use ApiPlatform\Metadata\ApiResource; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** A book. */ #[ORM\Entity] #[ApiResource] class Book { /** The ID of this book. */ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; /** The ISBN of this book (or null if doesn't have one). */ #[ORM\Column(nullable: true)] public ?string $isbn = null; /** The title of this book. */ #[ORM\Column] public string $title = ''; /** The description of this book. */ #[ORM\Column(type: 'text')] public string $description = ''; /** The author of this book. */ #[ORM\Column] public string $author = ''; /** The publication date of this book. */ #[ORM\Column] public ?\DateTimeImmutable $publicationDate = null; /** @var Review[] Available reviews for this book. */ #[ORM\OneToMany(targetEntity: Review::class, mappedBy: 'book', cascade: ['persist', 'remove'])] public iterable $reviews; public function __construct() ``` -------------------------------- ### NelmioCorsBundle Configuration Source: https://api-platform.com/docs/v3.4/admin/getting-started Sample configuration for NelmioCorsBundle to expose the Link HTTP header and send proper CORS headers. ```yaml # config/packages/nelmio_cors.yaml nelmio_cors: paths: '^/api/': origin_regex: true allow_origin: ['^http://localhost:[0-9]+'] # You probably want to change this regex to match your real domain allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] allow_headers: ['Content-Type', 'Authorization'] expose_headers: ['Link'] max_age: 3600 ``` -------------------------------- ### Start Docker Compose with Custom Configuration Source: https://api-platform.com/docs/v3.4/distribution Starts the web server on port 8080 with HTTPS disabled, overriding default server name and trusted hosts. ```bash SERVER_NAME=localhost:80 HTTP_PORT=8080 TRUSTED_HOSTS=localhost docker compose up --wait ``` -------------------------------- ### Clear Cache Source: https://api-platform.com/docs/v3.4/admin/getting-started Command to clear the cache to apply NelmioCorsBundle configuration changes. ```bash docker compose exec php \ bin/console cache:clear --env=prod ``` -------------------------------- ### Schema Configuration for Model Scaffolding Source: https://api-platform.com/docs/v3.4/schema-generator/getting-started A YAML configuration file for generating data models for an address book using Schema.org types. ```yaml # api/config/schema.yaml # The list of types and properties we want to use types: # Parent class of Person Thing: properties: name: ~ Person: # Enable the generation of the class hierarchy (not enabled by default) parent: ~ properties: familyName: ~ givenName: ~ additionalName: ~ address: ~ PostalAddress: properties: # Force the type of the addressCountry property to text addressCountry: { range: "Text" } addressLocality: ~ addressRegion: ~ postOfficeBoxNumber: ~ postalCode: ~ streetAddress: ~ ``` -------------------------------- ### Build Docker Images Source: https://api-platform.com/docs/v3.4/distribution Builds the Docker images for the API Platform services without using the cache. ```bash docker compose build --no-cache ``` -------------------------------- ### API Platform v3.4 Bootstrap Example Source: https://api-platform.com/docs/v3.4/core/bootstrap This code snippet illustrates the setup of various actions, factories, and routes for API Platform v3.4, culminating in the handling of an HTTP request. ```php $paginationOptions = new PaginationOptions(); $openApiOptions = new OpenApiOptions('API Platform'); $jsonSchemaTypeFactory = new TypeFactory($resourceClassResolver); $jsonSchemaFactory = new SchemaFactory($jsonSchemaTypeFactory, $resourceMetadataFactory, $propertyNameCollectionFactory, $propertyMetadataFactory, $nameConverter, $resourceClassResolver); $openApiFactory = new OpenApiFactory($resourceNameCollectionFactory, $resourceMetadataFactory, $propertyNameCollectionFactory, $propertyMetadataFactory, $jsonSchemaFactory, $jsonSchemaTypeFactory, $filterLocator); $documentationAction = new DocumentationAction($openApiFactory); $routes->add('api_doc', new Route('/docs.{_format}', ['_controller' => $documentationAction, '_format' => null, '_api_respond' => true])); $entryPointAction = new EntrypointAction($resourceNameCollectionFactory); $routes->add('api_entrypoint', new Route('/{index}.{_format}', ['_controller' => $entryPointAction, '_format' => null, '_api_respond' => true, 'index' => 'index'], ['index' => 'index'])); $contextAction = new ContextAction($jsonLdContextBuilder, $resourceNameCollectionFactory, $resourceMetadataFactory); $routes->add('api_jsonld_context', new Route('/contexts/{shortName}.{_format}', ['_controller' => $contextAction, '_format' => 'jsonld', '_api_respond' => true], ['shortName' => '.+'])); $notExposedAction = new NotExposedAction(); $routes->add('api_genid', new Route('/.well-known/genid/{id}', ['_controller' => $notExposedAction, '_format' => 'text', '_api_respond' => true])); $controllerResolver = new ControllerResolver(); $argumentResolver = new ArgumentResolver(); $kernel = new HttpKernel($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response); ``` -------------------------------- ### Bootstrap Next.js App Source: https://api-platform.com/docs/v3.4/distribution Command to bootstrap a Next.js app using API Platform's client generator. ```bash docker compose exec pwa \ pnpm create @api-platform/client ``` -------------------------------- ### Provider and Processor Collection Setup Source: https://api-platform.com/docs/v3.4/core/bootstrap Illustrates the creation of container-like objects for state providers and state processors, using anonymous classes implementing ContainerInterface. ```php $providerCollection = new class implements ContainerInterface { public array $providers = []; public function get($id) { return $this->providers[$id]; } public function has($id): bool { return isset($this->providers[$id]); } }; $stateProviders = new CallableProvider($providerCollection); $processorCollection = new class implements ContainerInterface { public array $processors = []; public function get($id) { return $this->processors[$id]; } public function has($id): bool { return isset($this->processors['id']); } }; $stateProcessors = new CallableProcessor($processorCollection); ``` -------------------------------- ### GraphQL query to read a greeting Source: https://api-platform.com/docs/v3.4/distribution Example GraphQL query to read a greeting by its ID. ```graphql { greeting(id: "/greetings/1") { id name _id } } ``` -------------------------------- ### Initial YAML Configuration Example Source: https://api-platform.com/docs/v3.4/core/security An initial example showing security configuration for a Book resource in YAML, including a specific rule for PUT operations. ```yaml resources: App\Entity\Book: operations: ApiPlatform\Metadata\Get: ~ ApiPlatform\Metadata\GetCollectionPut: securityPostDenormalize: "is_granted('ROLE_ADMIN') or (object.owner == user and previous_object.owner == user)" # ... ``` -------------------------------- ### Start Minikube Cluster Source: https://api-platform.com/docs/v3.4/deployment/minikube Starts Minikube with a Docker registry and the Kubernetes dashboard enabled. ```bash minikube start --addons registry --addons dashboard ``` -------------------------------- ### Validation Error Response Source: https://api-platform.com/docs/v3.4/distribution Example JSON response showing validation errors in Hydra format. ```json { "@context": "/contexts/ConstraintViolationList", "@type": "ConstraintViolationList", "hydra:title": "An error occurred", "hydra:description": "isbn: This value is neither a valid ISBN-10 nor a valid ISBN-13.\ntitle: This value should not be blank.", "violations": [ { "propertyPath": "isbn", "message": "This value is neither a valid ISBN-10 nor a valid ISBN-13." }, { "propertyPath": "title", "message": "This value should not be blank." } ] } ``` -------------------------------- ### Review Entity with Doctrine ORM Attributes Source: https://api-platform.com/docs/v3.4 Example of a Review entity mapped to database tables using Doctrine ORM attributes. ```php namespace App\Entity; use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; /** A review of a book. */ #[ORM\Entity] #[ApiResource] class Review { /** The ID of this review. */ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; /** The rating of this review (between 0 and 5). */ #[ORM\Column(type: 'smallint')] public int $rating = 0; /** The body of the review. */ #[ORM\Column(type: 'text')] public string $body = ''; /** The author of the review. */ #[ORM\Column] public string $author = ''; /** The date of publication of this review. */ #[ORM\Column] public ?\DateTimeImmutable $publicationDate = null; /** The book this review is about. */ #[ORM\ManyToOne(inversedBy: 'reviews')] public ?Book $book = null; public function getId(): ?int ``` -------------------------------- ### Review Entity with Doctrine ORM Attributes Source: https://api-platform.com/docs/v3.4/distribution Example of a Review entity mapped to database tables using Doctrine ORM attributes. ```php namespace App\Entity; use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; /** A review of a book. */ #[ORM\Entity] #[ApiResource] class Review { /** The ID of this review. */ #[ORM\Id, ORM\Column, ORM\GeneratedValue] private ?int $id = null; /** The rating of this review (between 0 and 5). */ #[ORM\Column(type: 'smallint')] public int $rating = 0; /** The body of the review. */ #[ORM\Column(type: 'text')] public string $body = ''; /** The author of the review. */ #[ORM\Column] public string $author = ''; /** The date of publication of this review. */ #[ORM\Column] public ?\DateTimeImmutable $publicationDate = null; /** The book this review is about. */ #[ORM\ManyToOne(inversedBy: 'reviews')] public ?Book $book = null; public function getId(): ?int ``` -------------------------------- ### Start Skaffold in Dev Mode Source: https://api-platform.com/docs/v3.4/deployment/minikube Starts Skaffold in development mode from the helm directory for continuous deployment. ```bash cd ./helm skaffold dev ``` -------------------------------- ### Service Instantiation Example Source: https://api-platform.com/docs/v3.4/core/bootstrap This snippet demonstrates the instantiation and configuration of various normalizers and services used in the API Platform core bootstrap process. It includes examples for Hydra, HAL, JSON-LD, and general object normalization. ```php /**new UriVariablesConverter($propertyMetadataFactory, $resourceMetadataFactory, $uriVariableTransformers)*/ null, ); $serializerContextBuilder = new SerializerContextBuilder($resourceMetadataFactory); $objectNormalizer = new ObjectNormalizer(); $nameConverter = new MetadataAwareNameConverter($classMetadataFactory); $jsonLdContextBuilder = new JsonLdContextBuilder($resourceNameCollectionFactory, $resourceMetadataFactory, $propertyNameCollectionFactory, $propertyMetadataFactory, $apiUrlGenerator, $iriConverter, $nameConverter); $jsonLdItemNormalizer = new JsonLdItemNormalizer($resourceMetadataFactory, $propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $jsonLdContextBuilder, $propertyAccessor, $nameConverter, $classMetadataFactory, $defaultContext, /** resource access checker **/ null); $jsonLdObjectNormalizer = new JsonLdObjectNormalizer($objectNormalizer, $iriConverter, $jsonLdContextBuilder); $jsonLdEncoder = new JsonLdEncoder('jsonld', new JsonEncoder()); $problemConstraintViolationListNormalizer = new ProblemConstraintViolationListNormalizer([], $nameConverter, $defaultContext); $hydraCollectionNormalizer = new HydraCollectionNormalizer($jsonLdContextBuilder, $resourceClassResolver, $iriConverter, $resourceMetadataFactory, $defaultContext); $hydraPartialCollectionNormalizer = new PartialCollectionViewNormalizer($hydraCollectionNormalizer, $configuration['collection']['pagination']['page_parameter_name'], $configuration['collection']['pagination']['enabled_parameter_name'], $resourceMetadataFactory, $propertyAccessor); $hydraCollectionFiltersNormalizer = new CollectionFiltersNormalizer($hydraPartialCollectionNormalizer, $resourceMetadataFactory, $resourceClassResolver, $filterLocator); $hydraErrorNormalizer = new HydraErrorNormalizer($apiUrlGenerator, $debug, $defaultContext); $hydraEntrypointNormalizer = new HydraEntrypointNormalizer($resourceMetadataFactory, $iriConverter, $apiUrlGenerator); $hydraDocumentationNormalizer = new HydraDocumentationNormalizer($resourceMetadataFactory, $propertyNameCollectionFactory, $propertyMetadataFactory, $resourceClassResolver, $apiUrlGenerator, $nameConverter); $hydraConstraintViolationNormalizer = new HydraConstraintViolationListNormalizer($apiUrlGenerator, [], $nameConverter); $problemErrorNormalizer = new ErrorNormalizer($debug, $defaultContext); // $expressionLanguage = new ExpressionLanguage(); // $resourceAccessChecker = new ResourceAccessChecker( // $expressionLanguage, // ); $itemNormalizer = new ItemNormalizer( $propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, $logger, $resourceMetadataFactory, /**$resourceAccessChecker **/ null, $defaultContext ); $arrayDenormalizer = new ArrayDenormalizer(); $problemNormalizer = new ProblemNormalizer($debug, $defaultContext); $jsonserializableNormalizer = new JsonSerializableNormalizer($classMetadataFactory, $nameConverter, $defaultContext); $dateTimeNormalizer = new DateTimeNormalizer($defaultContext); $dataUriNormalizer = new DataUriNormalizer(); $dateIntervalNormalizer = new DateIntervalNormalizer($defaultContext); $dateTimeZoneNormalizer = new DateTimeZoneNormalizer(); $constraintViolationListNormalizer = new ConstraintViolationListNormalizer($defaultContext, $nameConverter); $unwrappingDenormalizer = new UnwrappingDenormalizer($propertyAccessor); $halItemNormalizer = new HalItemNormalizer($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, $defaultContext, $resourceMetadataFactory, /** resourceAccessChecker **/ null); $halItemNormalizer = new HalItemNormalizer($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, $defaultContext, $resourceMetadataFactory, /** resourceAccessChecker **/ null); $halEntrypointNormalizer = new HalEntrypointNormalizer($resourceMetadataFactory, $iriConverter, $apiUrlGenerator); $halCollectionNormalizer = new HalCollectionNormalizer($resourceClassResolver, $configuration['collection']['pagination']['page_parameter_name'], $resourceMetadataFactory); $halObjectNormalizer = new HalObjectNormalizer($objectNormalizer, $iriConverter); $openApiNormalizer = new OpenApiNormalizer($objectNormalizer); $list = new \SplPriorityQueue(); $list->insert($unwrappingDenormalizer, 1000); $list->insert($halItemNormalizer, -890); $list->insert($hydraConstraintViolationNormalizer, -780); $list->insert($hydraEntrypointNormalizer, -800); $list->insert($hydraErrorNormalizer, -800); $list->insert($hydraCollectionFiltersNormalizer, -800); $list->insert($halEntrypointNormalizer, -800); $list->insert($halCollectionNormalizer, -985); $list->insert($halObjectNormalizer, -995); ``` -------------------------------- ### Example Functional Test: Get Collection Source: https://api-platform.com/docs/v3.4/distribution/testing An example of a functional test for retrieving a collection of books. ```php request('GET', '/books'); $this->assertResponseIsSuccessful(); // Asserts that the returned content type is JSON-LD (the default) $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); // Asserts that the returned JSON is a superset of this one $this->assertJsonContains([ '@context' => '/contexts/Book', '@id' => '/books', '@type' => 'hydra:Collection', 'hydra:totalItems' => 100, 'hydra:view' => [ '@id' => '/books?page=1', '@type' => 'hydra:PartialCollectionView', 'hydra:first' => '/books?page=1', 'hydra:last' => '/books?page=4', 'hydra:next' => '/books?page=2', ], ]); // Because test fixtures are automatically loaded between each test, you can assert on them $this->assertCount(30, $response->toArray()['hydra:member']); // Asserts that the returned JSON is validated by the JSON Schema generated for this resource by API Platform // This generated JSON Schema is also used in the OpenAPI spec! $this->assertMatchesResourceCollectionJsonSchema(Book::class); } public function testCreateBook(): void { $response = static::createClient()->request('POST', '/books', ['json' => [ 'isbn' => '0099740915', 'title' => 'The Handmaid\'s Tale', 'description' => 'Brilliantly conceived and executed, this powerful evocation of twenty-first century America gives full rein to Margaret Atwood\'s devastating irony, wit and astute perception.', 'author' => 'Margaret Atwood', 'publicationDate' => '1985-07-31T00:00:00+00:00', ]]); $this->assertResponseStatusCodeSame(201); $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); $this->assertJsonContains([ '@context' => '/contexts/Book', '@type' => 'Book', 'isbn' => '0099740915', 'title' => 'The Handmaid\'s Tale', 'description' => 'Brilliantly conceived and executed, this powerful evocation of twenty-first century America gives full rein to Margaret Atwood\'s devastating irony, wit and astute perception.', 'author' => 'Margaret Atwood', 'publicationDate' => '1985-07-31T00:00:00+00:00', 'reviews' => [], ]); $this->assertMatchesRegularExpression('~^/books/\d+$~', $response->toArray()['@id']); $this->assertMatchesResourceItemJsonSchema(Book::class); } public function testCreateInvalidBook(): void { static::createClient()->request('POST', '/books', ['json' => [ 'isbn' => 'invalid', ]]); $this->assertResponseStatusCodeSame(422); ``` -------------------------------- ### Bring up the full project Source: https://api-platform.com/docs/v3.4/deployment/docker-compose Command to bring up the entire project after building the 'pwa' service. ```bash SERVER_NAME=http://localhost \ MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ TRUSTED_HOSTS='^localhost|php$' \ APP_SECRET=!ChangeMe! \ CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \ POSTGRES_PASSWORD=!ChangeMe! \ docker compose -f compose.yaml -f compose.prod.yaml up -d --wait ``` -------------------------------- ### Install Google Cloud SDK Source: https://api-platform.com/docs/v3.4/deployment/kubernetes Command to download and install the Google Cloud SDK. ```bash curl https://sdk.cloud.google.com | bash ``` -------------------------------- ### Build Docker Images Source: https://api-platform.com/docs/v3.4/deployment/minikube Builds the necessary Docker images for the API Platform components. ```bash docker build -t localhost:5000/php api --target api_platform_php docker build -t localhost:5000/caddy api --target api_platform_caddy docker build -t localhost:5000/pwa pwa --target api_platform_pwa_prod ``` -------------------------------- ### Caddyfile Routing Rule Source: https://api-platform.com/docs/v3.4/distribution/caddy Example of modifying the Caddyfile to route requests starting with /admin to the API. ```caddyfile # Matches requests for HTML documents, for static files and for Next.js files, # except for known API paths and paths with extensions handled by API Platform @pwa expression `( {header.Accept}.matches("\\btext/html\\b") && !{path}.matches("(?i)(?:^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") && !{path}.matches("(?i)(?:^/admin|^/docs|^/graphql|^/bundles/|^/_profiler|^/_wdt|\\.(?:json|html$|csv$|ya?ml$|xml$))") )` ``` -------------------------------- ### Review Entity Source: https://api-platform.com/docs/v3.4/distribution Defines the Review resource type with its properties and the #[ApiResource] attribute. ```php id; } } ``` -------------------------------- ### Install Foundry and Doctrine/DoctrineFixturesBundle Source: https://api-platform.com/docs/v3.4/distribution/testing Installs the necessary packages for creating data fixtures. ```bash docker compose exec php \ composer require --dev foundry orm-fixtures ``` -------------------------------- ### Book Entity Source: https://api-platform.com/docs/v3.4/distribution Defines the Book resource type with its properties and the #[ApiResource] attribute. ```php reviews = new ArrayCollection(); } public function getId(): ?int { return $this->id; } } ``` -------------------------------- ### Start the development server Source: https://api-platform.com/docs/v3.4/create-client/react Start the integrated web server to view the application. ```bash npm run dev ``` -------------------------------- ### Explicitly Handling JSON Format Source: https://api-platform.com/docs/v3.4/core/upgrade-guide Example of explicitly handling the 'json' format when it's not enabled by default. ```yaml formats: json: ['application/json'] ``` -------------------------------- ### Composer.json Update for Standalone Packages Source: https://api-platform.com/docs/v3.4/core/upgrade-guide Example of updating composer.json to use standalone API Platform packages. ```json { "require": { "api-platform/core": "^3", "api-platform/symfony": "^3 || ^4" // also add the extra packages you need, like "api-platform/doctrine-orm" } } ``` -------------------------------- ### Install VichUploaderBundle Source: https://api-platform.com/docs/v3.4/core/file-upload Installs the VichUploaderBundle using Composer. ```bash docker compose exec php \ composer require vich/uploader-bundle ``` -------------------------------- ### Build and start the php service Source: https://api-platform.com/docs/v3.4/deployment/docker-compose Command to build and start the php service container with specific environment variables. ```bash SERVER_NAME=http://localhost \ MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ TRUSTED_HOSTS='^localhost|php$' \ APP_SECRET=!ChangeMe! \ CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \ POSTGRES_PASSWORD=!ChangeMe! \ docker compose -f compose.yaml -f compose.prod.yaml up -d --build --wait php ``` -------------------------------- ### Review Entity with Validation Constraints Source: https://api-platform.com/docs/v3.4/distribution PHP code showing the Review entity with added validation constraints. ```php use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; #[ORM\Column(type: 'smallint')] #[Assert\Range(min: 0, max: 5)] public int $rating = 0; #[ORM\Column(type: 'text')] #[Assert\NotBlank] public string $body = ''; #[ORM\Column] #[Assert\NotBlank] public string $author = ''; #[ORM\Column] #[Assert\NotNull] public ?\DateTimeImmutable $publicationDate = null; #[ORM\ManyToOne(inversedBy: 'reviews')] #[Assert\NotNull] public ?Book $book = null; public function getId(): ?int ``` -------------------------------- ### Install DAMADoctrineTestBundle Source: https://api-platform.com/docs/v3.4/distribution/testing Install the DAMADoctrineTestBundle to automatically reset the database before each test. ```bash docker compose exec php \ composer require --dev dama/doctrine-test-bundle ``` -------------------------------- ### Setting Custom HTTP Cache Headers Per Operation Source: https://api-platform.com/docs/v3.4/core/performance Example of setting different cache headers for a specific operation (GET) on a resource. ```php use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Get; #[ApiResource] #[Get( cacheHeaders: [ 'max_age' => 60, 'shared_max_age' => 120, ] )] class Book { // ... } ``` -------------------------------- ### Example .env file Source: https://api-platform.com/docs/v3.4/deployment/traefik An example of an environment file to define necessary variables for the deployment. ```env CONTAINER_REGISTRY_BASE=quay.io/api-platform DOMAIN_NAME=localhost HTTP_OR_SSL=https:// DB_NAME=api-platform-db-name DB_PASS=YouMustChangeThisPassword DB_USER=api-platform JWT_KEY=!UnsecureChangeMe! SUBDOMAINS_LIST=(admin|api|mercure) ``` -------------------------------- ### Clone your project repository Source: https://api-platform.com/docs/v3.4/deployment/docker-compose Copy your project files to the server using Git. Replace and with your actual GitHub details. ```bash git clone git@github.com:/.git ```