From f121b177d62beb7ed086fac53c0cf59069a26351 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 11:15:35 +0200 Subject: [PATCH 01/33] Update event listener configuration for API Platform 4.0 Updated the documentation to reflect the requirement of `use_symfony_listeners: true` for activating event listeners in API Platform 4.0. Also reformatted existing notes for better clarity and added separation lines for improved readability. --- core/events.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/events.md b/core/events.md index 1c535d79d4a..efa80706345 100644 --- a/core/events.md +++ b/core/events.md @@ -1,9 +1,12 @@ # The Event System -In API Platform 3.2 you may need `event_listeners_backward_compatibility_layer: true` to keep event listeners activated. +> [!WARNING] +> In API Platform 4.0 with Symfony, you need `use_symfony_listeners: true` to activate event listeners. -Note: using Kernel event with API Platform should be mostly limited to tweaking the generated HTTP response. Also, GraphQL is **not supported**. -[For most use cases, better extension points, working both with REST and GraphQL, are available](extending.md). +--- + +> [!NOTE] +> Using Kernel event with API Platform should be mostly limited to tweaking the generated HTTP response. Also, GraphQL is **not supported**. API Platform Core implements the [Action-Domain-Responder](https://github.com/pmjones/adr) pattern. This implementation is covered in depth in the [Creating custom operations and controllers](operations.md#creating-custom-operations-and-controllers) From 0d7e614f78b6e17d77cdddd82f765013c4a4574e Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 11:15:56 +0200 Subject: [PATCH 02/33] Add documentation on system providers and processors This commit introduces detailed documentation on the workflow of state providers and processors in the system. It includes a schema, examples of decorating providers and processors, and specific implementations for both Symfony and Laravel frameworks. --- core/extending.md | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/core/extending.md b/core/extending.md index 73e393654c4..d0b5a082b10 100644 --- a/core/extending.md +++ b/core/extending.md @@ -36,3 +36,119 @@ For instance, if you want to send a mail after a resource has been persisted, bu To replace existing API Platform services with your decorators, [check out how to decorate services](https://symfony.com/doc/current/service_container/service_decoration.html).

Service Decoration screencast
Watch the Service Decoration screencast

+ +## System providers and processors + +The system is based on a workflow composed of **state providers** and **state processors** + +The schema below describes them: + +```mermaid +--- +title: System providers and processors +--- +flowchart TB + C1(ReadProvider) --> C2(AccessCheckerProvider) + C2 --> C3(DeserializeProvider) + C3 --> C4(ParameterProvider) + C4 --> C5(ValidateProcessor) + C5 --> C6(WriteProcessor) + C6 --> C7(SerializeProcessor) +``` + +### Symfony Access Checker Provider + +When using Symfony, the access checker provider is used at three different stages: +- `api_platform.state_provider.access_checker.post_validate` decorates the ValidateProvider +- `api_platform.state_provider.access_checker.post_deserialize` decorates the DeserializeProvider +- `api_platform.state_provider.access_checker` decorates the ReadProvider + + +### Decoration example + +Here is an example of the decoration of the RespondProcessor: + +Starts by creating your `CustomRespondProcessor`: +```php +processor)($data, $resourceClass, $operationName, $context); + + // You can add post-write code here. + + return $writtenObject; + } +} +``` + +Now you should decorate the RespondProcessor with the CustomRespondProcessor using Symfony or Laravel: + +### Decorating the RespondProcessor with Symfony + +With Symfony you can simply do that by adding the `#[AsDecorator]` attribute as following: + +```php +namespace App\State; + +use ApiPlatform\State\ProcessorInterface; + +#[AsDecorator(decorates: 'api_platform.state.processor.respond_processor',)] +final class CustomRespondProcessor implements ProcessorInterface +{ + // ... +} +``` + +or in the `services.yaml` by defining: + +```yaml +# api/config/services.yaml +services: + # ... + App\State\CustomRespondProcessor: + decorates: api_platform.state.processor.respond_processor +``` + +And that's it! + +### Decorating the RespondProcessor with Laravel +```php +app->singleton(CustomRespondProcessor::class, function (Application $app) { + return new CustomRespondProcessor(); + }); + + $this->app->extend(RespondProcessor::class, function (RespondProcessor $respondProcessor, Application $app) { + return new CustomRespondProcessor($respondProcessor); + }); + } + + public function boot(): void + { + } +} +``` From e2a88a4ab930d66fbb35cbf2df04508faabcd3ca Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 11:16:11 +0200 Subject: [PATCH 03/33] Update GraphQL docs to include Laravel-specific instructions This update adds detailed instructions for enabling and configuring GraphQL in a Laravel environment, complementing the existing Symfony guidance. It covers installation, route configurations, disabling features, custom resolvers, and altering default settings specific to Laravel, ensuring comprehensive and platform-specific documentation. --- core/graphql.md | 466 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 383 insertions(+), 83 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index 3392112f33c..bd5bfeec782 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -10,23 +10,29 @@ Once enabled, you have nothing to do: your schema describing your API is automat ## Enabling GraphQL -To enable GraphQL and its IDE (GraphiQL and GraphQL Playground) in your API, simply require the [graphql-php](https://webonyx.github.io/graphql-php/) package using Composer and clear the cache one more time: +To enable GraphQL and its IDE (GraphiQL and GraphQL Playground) in your API, simply require the [API Platform GraphQL](https://github.com/api-platform/graphql) package using Composer: +### Symfony installation ```console -docker compose exec php sh -c ' - composer require webonyx/graphql-php - bin/console cache:clear -' +docker compose exec php sh -c 'composer require api-platform/graphql' +``` + +### Laravel installation (without Docker) +```console + composer require api-platform/graphql ``` You can now use GraphQL at the endpoint: `https://localhost:8443/graphql`. -*Note:* If you used [Symfony Flex to install API Platform](../symfony/index.md#using-symfony-flex-and-composer-advanced-users), URLs will be prefixed with `/api` by default. For example, the GraphQL endpoint will be: `https://localhost:8443/api/graphql`. +> [!NOTE] +> If you used [the Symfony Variant thanks to Symfony Flex](../symfony/index.md#using-symfony-flex-and-composer-advanced-users) or the Laravel variant, URLs will be prefixed with `/api` by default. For example, the GraphQL endpoint will be: `https://localhost:8443/api/graphql`. ## Changing Location of the GraphQL Endpoint - Sometimes you may want to have the GraphQL endpoint at a different location. This can be done by manually configuring the GraphQL controller. +### Symfony config for routes + +Using the Symfony variant we can do this modification by adding the following code: ```yaml # api/config/routes.yaml api_graphql_entrypoint: @@ -37,14 +43,29 @@ api_graphql_entrypoint: Change `/api/graphql` to the URI you wish the GraphQL endpoint to be accessible on. +### Laravel config for routes + +Using the Laravel variant we can do this modification by adding the following code: +```php +// routes/web.php +use Illuminate\Support\Facades\Route; +use ApiPlatform\GraphQL\Action\EntrypointAction; + +Route::post('/api/graphql', EntrypointAction::class) + ->name('api_graphql_entrypoint'); +``` + +Change `/api/graphql` to the URI you wish the GraphQL endpoint to be accessible on. + ## GraphiQL -If Twig is installed in your project, go to the GraphQL endpoint with your browser. You will see a nice interface provided by GraphiQL to interact with your API. +Go to the GraphQL endpoint with your browser, you will see a nice interface provided by GraphiQL to interact with your API. The GraphiQL IDE can also be found at `/graphql/graphiql`. If you need to disable it, it can be done in the configuration: +### Disable GraphiQL with Symfony ```yaml # api/config/packages/api_platform.yaml api_platform: @@ -54,9 +75,26 @@ api_platform: # ... ``` +### Disable GraphiQL with Laravel +```php + [ + 'graphiql' => [ + 'enabled' => false, + ] + ], +]; +``` + ### Add another Location for GraphiQL -If you want to add a different location besides `/graphql/graphiql`, you can do it like this: +Sometimes you may want to have the GraphiQL at a different location. This can be done by manually configuring the GraphiQL controller. + +### Symfony config routes for GraphiQL +If you want to add a different location besides `/graphql/graphiql`, you can do it like this if you are using the Symfony variant: ```yaml # app/config/routes.yaml @@ -65,13 +103,27 @@ graphiql: controller: api_platform.graphql.action.graphiql ``` +### Laravel config routes for GraphiQL + +If you want to add a different location besides `/graphql/graphiql`, you can do it like this if you are using the Laravel variant: +```php +// routes/web.php +use Illuminate\Support\Facades\Route; +use ApiPlatform\GraphQL\Action\GraphiQlAction; + +Route::post('/docs/graphiql', GraphiQlAction::class) + ->name('graphiql'); +``` + ## GraphQL Playground Another IDE is by default included in API Platform: GraphQL Playground. It can be found at `/graphql/graphql_playground`. -You can disable it if you want in the configuration: +You can disable it if you want in the configuration. + +### Disable GraphQL Playground with Symfony ```yaml # api/config/packages/api_platform.yaml @@ -82,9 +134,27 @@ api_platform: # ... ``` +### Disable GraphQL Playground with Laravel + +```php + [ + 'graphql_playground' => [ + 'enabled' => false, + ] + ], +]; +``` + ### Add another Location for GraphQL Playground +You can add a different location besides `/graphql/graphql_playground`. + +### Symfony config routes for GraphQL Playground -You can add a different location besides `/graphql/graphql_playground`: +Using the Symfony variant we can do this modification by adding the following code: ```yaml # app/config/routes.yaml @@ -93,10 +163,24 @@ graphql_playground: controller: api_platform.graphql.action.graphql_playground ``` +### Laravel config routes for GraphQL Playground + +Using the Laravel variant we can do this modification by adding the following code: +```php +// routes/web.php +use Illuminate\Support\Facades\Route; +use ApiPlatform\GraphQL\Action\GraphQlPlaygroundAction; + +Route::post('/docs/graphql_playground', GraphQlPlaygroundAction::class) + ->name('graphql_playground'); +``` + ## Modifying or Disabling the Default IDE When going to the GraphQL endpoint, you can choose to launch the IDE you want. +### Symfony config to modifying the default IDE + ```yaml # api/config/packages/api_platform.yaml api_platform: @@ -106,8 +190,23 @@ api_platform: # ... ``` +### Laravel config to modifying the default IDE + +```php + [ + // Choose between graphiql or graphql-playground + 'default_ide' => 'graphql-playground', + ], +]; +``` + You can also disable this feature by setting the configuration value to `false`. +### Symfony config to disable default IDE ```yaml # api/config/packages/api_platform.yaml api_platform: @@ -116,10 +215,24 @@ api_platform: # ... ``` +### Laravel config to disable default IDE +```php + [ + 'default_ide' => false, + ], +]; +``` + ## Disabling the Introspection Query For security reason, the introspection query should be disabled to not expose the GraphQL schema. + +### Symfony config to disable the Introspection Query If you need to disable it, it can be done in the configuration: ```yaml @@ -130,11 +243,27 @@ api_platform: # ... ``` +### Laravel config to disable the Introspection Query +If you need to disable it, it can be done in the configuration: + +```php + [ + 'introspection' => false, + ], +]; +``` + ## Request with `application/graphql` Content-Type If you wish to send a [POST request using the `application/graphql` Content-Type](https://graphql.org/learn/serving-over-http/#post-request), you need to enable it in the [allowed formats of API Platform](content-negotiation.md#configuring-formats-globally): +### Symfony config for GraphQL Content-Type + ```yaml # api/config/packages/api_platform.yaml api_platform: @@ -143,8 +272,26 @@ api_platform: graphql: ['application/graphql'] ``` +### Laravel config for GraphQL Content-Type + +```php + [ + 'graphql' => [ + 'application/graphql', + ], + ], +]; +``` + ## Operations +> [!NOTE] +> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”. + To understand what an operation is, please refer to the [operations documentation](operations.md). For GraphQL, the operations are defined by using the `Query`, `QueryCollection`, `Mutation`, `DeleteMutation` and `Subscription` attributes. @@ -183,6 +330,7 @@ class Book ``` ```yaml +#The YAML syntax is only supported for Symfony resources: App\Entity\Book: graphQlOperations: @@ -192,6 +340,7 @@ resources: ``` ```xml + [ + 'nesting_separator' => __ + ], +]; +``` In this case, your query will be: @@ -2521,9 +2766,12 @@ You can also check the documentation of [graphql-php](https://webonyx.github.io/ The big difference in API Platform is that the value is already serialized when it's received in your type class. Similarly, you would not want to denormalize your parsed value since it will be done by API Platform later. + +#### Custom Types config for Symfony + If you use autoconfiguration (the default Symfony configuration) in your application, then you are done! -Else, you need to tag your type class like this: +Else, you need to tag your type class like this, if you're using Symfony : ```yaml # api/config/services.yaml @@ -2538,8 +2786,42 @@ Your custom type is now registered and is available in the `TypesContainer`. To use it please [modify the extracted types](#modify-the-extracted-types) or use it directly in [custom queries](#custom-queries) or [custom mutations](#custom-mutations). + +#### Custom Types config for Laravel + +If you are using Laravel tag your type with: + +```php +app->tag([DateTimeType::class], TypeInterface::class); + } + + public function boot(): void + { + } +} +``` + +Your custom type is now registered and is available in the `TypesContainer`. + +To use it please [modify the extracted types](#modify-the-extracted-types) or use it directly in [custom queries](#custom-queries) or [custom mutations](#custom-mutations). + ## Modify the Extracted Types +> [!WARNING] +> This part is only supported for API Platform with Symfony + The GraphQL schema and its types are extracted from your resources. In some cases, you would want to modify the extracted types for instance to use your custom ones. @@ -2606,7 +2888,10 @@ if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType() All `DateTimeInterface` properties will have the `DateTime` type in this example. -## Changing the Serialization Context Dynamically +## Changing the Serialization Context Dynamically (only for Symfony) + +> [!WARNING] +> This part is only supported for API Platform with Symfony [As REST](serialization.md#changing-the-serialization-context-dynamically), it's possible to add dynamically a (de)serialization group when resolving a query or a mutation. @@ -2649,21 +2934,22 @@ final class BookContextBuilder implements SerializerContextBuilderInterface } ``` -## Export the Schema in SDL +## Export the Schema in SDL + +> [!WARNING] +> These commands are only available for API Platform with Symfony! You may need to export your schema in SDL (Schema Definition Language) to import it in some tools. The `api:graphql:export` command is provided to do so: ```shell-session -docker compose exec php \ bin/console api:graphql:export -o path/to/your/volume/schema.graphql ``` Since the command prints the schema to the output if you don't use the `-o` option, you can also use this command: ```shell-session -docker compose exec php \ bin/console api:graphql:export > path/in/host/schema.graphql ``` @@ -2784,6 +3070,7 @@ Following the specification, the upload must be done with a `multipart/form-data You need to enable it in the [allowed formats of API Platform](content-negotiation.md#configuring-formats-globally): +#### Modifying allowed formats with Symfony ```yaml # api/config/packages/api_platform.yaml api_platform: @@ -2792,6 +3079,19 @@ api_platform: multipart: ['multipart/form-data'] ``` +#### Modifying allowed formats with Laravel +```php + [ + // ... + 'multipart' => ['multipart/form-data'] + ], +]; +``` + You can now upload files using the `createMediaObject` mutation, for details check [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec) and for an example implementation for the Apollo client check out [Apollo Upload Client](https://github.com/jaydenseric/apollo-upload-client). From 060b4a627607482225b9a9b1a4748f2cffa52a16 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 11:28:11 +0200 Subject: [PATCH 04/33] Remove specific framework & Docker for GraphQL installation commands --- core/graphql.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index bd5bfeec782..59e21825adf 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -12,12 +12,6 @@ Once enabled, you have nothing to do: your schema describing your API is automat To enable GraphQL and its IDE (GraphiQL and GraphQL Playground) in your API, simply require the [API Platform GraphQL](https://github.com/api-platform/graphql) package using Composer: -### Symfony installation -```console -docker compose exec php sh -c 'composer require api-platform/graphql' -``` - -### Laravel installation (without Docker) ```console composer require api-platform/graphql ``` From 8495af21008ff7d05a57e29c3c867cfffc90fbc0 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 11:47:36 +0200 Subject: [PATCH 05/33] Refactor GraphQL & extending documentations for clarity and accuracy Updated terminology from "stages" to "providers and processors" for better clarity. Removed redundant sections to streamline information on custom mutations and configuration examples. --- core/extending.md | 3 +- core/graphql.md | 182 +++------------------------------------------- 2 files changed, 12 insertions(+), 173 deletions(-) diff --git a/core/extending.md b/core/extending.md index d0b5a082b10..822999b35bd 100644 --- a/core/extending.md +++ b/core/extending.md @@ -68,7 +68,8 @@ When using Symfony, the access checker provider is used at three different stage Here is an example of the decoration of the RespondProcessor: -Starts by creating your `CustomRespondProcessor`: +Starts by creating your `CustomRespondProcessor`: + ```php - -```php - ['type' => 'ID!']] - ), - new Mutation( - name: 'withCustomArgsMutation', - resolver: BookMutationResolver::class, - args: [ - 'sendMail' => [ - 'type' => 'Boolean!', - 'description' => 'Send a mail?' - ] - ] - ), - new Mutation( - name: 'disabledStagesMutation', - resolver: BookMutationResolver::class, - deserialize: false, - write: false - ) - ] -)] -class Book -{ - // ... -} -``` - -```yaml -#The YAML syntax is only supported for Symfony -resources: - App\Entity\Book: - graphQlOperations: - - class: ApiPlatform\Metadata\GraphQl\Query - - class: ApiPlatform\Metadata\GraphQl\QueryCollection - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: create - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: update - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: delete - - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: mutation - resolver: App\Resolver\BookMutationResolver - extraArgs: - id: - type: 'ID!' - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: withCustomArgsMutation - resolver: App\Resolver\BookMutationResolver - args: - sendMail: - type: 'Boolean!' - description: 'Send a mail?' - - class: ApiPlatform\Metadata\GraphQl\Mutation - name: disabledStagesMutation - resolver: App\Resolver\BookMutationResolver - deserialize: false - write: false -``` - -```xml - - - - - - - - - - - - - - - ID! - - - - - - - - - Boolean! - Send a mail? - - - - - - - - -``` - - - Note that you need to explicitly add the auto-generated queries and mutations if they are needed when configuring custom mutations, like it's done for the [operations](#operations). As the custom queries, you can define your own arguments if you don't want to use the default ones (extracted from your resource). @@ -884,38 +755,6 @@ You can also use the `extraArgs` property in case you need to add additional arg The arguments will be in `$context['args']['input']` of your resolvers. -Your custom mutations will be available like this: - -```graphql -{ - mutation { - mutationBook(input: {id: "/books/18", title: "The Fitz and the Fool"}) { - book { - title - } - } - } - - mutation { - withCustomArgsMutationBook(input: {sendMail: true, clientMutationId: "myId"}) { - book { - title - } - clientMutationId - } - } - - mutation { - disabledStagesMutationBook(input: {title: "The Fitz and the Fool"}) { - book { - title - } - clientMutationId - } - } -} -``` - ## Subscriptions Subscriptions are an [RFC](https://github.com/graphql/graphql-spec/blob/master/rfcs/Subscriptions.md#rfc-graphql-subscriptions) to allow a client to receive pushed realtime data from the server. @@ -1043,9 +882,9 @@ See the [Extending API Platform](extending.md) documentation for more informatio ### Disabling system providers and processors -If you need to, you can disable some stages done by the resolvers, for instance if you don't want your data to be validated. +If you need to, you can disable some states providers and state processors done by the resolvers, for instance if you don't want your data to be validated. -The following table lists the stages you can disable in your resource configuration. +The following table lists the system states providers and states processors you can disable in your resource configuration. | Attribute | Type | Default | Description | |----------------------------|--------|---------|-------------------------------------------| @@ -2760,8 +2599,7 @@ You can also check the documentation of [graphql-php](https://webonyx.github.io/ The big difference in API Platform is that the value is already serialized when it's received in your type class. Similarly, you would not want to denormalize your parsed value since it will be done by API Platform later. - -#### Custom Types config for Symfony +### Custom Types config for Symfony If you use autoconfiguration (the default Symfony configuration) in your application, then you are done! @@ -2781,7 +2619,7 @@ Your custom type is now registered and is available in the `TypesContainer`. To use it please [modify the extracted types](#modify-the-extracted-types) or use it directly in [custom queries](#custom-queries) or [custom mutations](#custom-mutations). -#### Custom Types config for Laravel +### Custom Types config for Laravel If you are using Laravel tag your type with: @@ -2928,7 +2766,7 @@ final class BookContextBuilder implements SerializerContextBuilderInterface } ``` -## Export the Schema in SDL +## Export the Schema in SDL > [!WARNING] > These commands are only available for API Platform with Symfony! From 044156e87c57610bc59dfd9aa6c73dba5addeef6 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:27:16 +0200 Subject: [PATCH 06/33] Fix capitalize title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 822999b35bd..634b0d0c60d 100644 --- a/core/extending.md +++ b/core/extending.md @@ -37,7 +37,7 @@ To replace existing API Platform services with your decorators, [check out how t

Service Decoration screencast
Watch the Service Decoration screencast

-## System providers and processors +## System Providers and Processors The system is based on a workflow composed of **state providers** and **state processors** From f51aa641a61ebf74e2e23b1a6957cbf8f0596ed2 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:27:41 +0200 Subject: [PATCH 07/33] Fix capitalize title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 634b0d0c60d..e943d9c7b30 100644 --- a/core/extending.md +++ b/core/extending.md @@ -64,7 +64,7 @@ When using Symfony, the access checker provider is used at three different stage - `api_platform.state_provider.access_checker` decorates the ReadProvider -### Decoration example +### Decoration Example Here is an example of the decoration of the RespondProcessor: From d88be0dd38427dd63245abf9cfbc29a993636292 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:28:10 +0200 Subject: [PATCH 08/33] Fix capitalize title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index bc1c1c54c39..dad81eee4f2 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -24,7 +24,7 @@ You can now use GraphQL at the endpoint: `https://localhost:8443/graphql`. ## Changing Location of the GraphQL Endpoint Sometimes you may want to have the GraphQL endpoint at a different location. This can be done by manually configuring the GraphQL controller. -### Symfony config for routes +### Symfony Config for Routes Using the Symfony variant we can do this modification by adding the following code: ```yaml From 8df3eeb50543ab350a823459a51d0ed90a05b9b9 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:28:40 +0200 Subject: [PATCH 09/33] Fix capitalize title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index dad81eee4f2..1442793480d 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -37,7 +37,7 @@ api_graphql_entrypoint: Change `/api/graphql` to the URI you wish the GraphQL endpoint to be accessible on. -### Laravel config for routes +### Laravel Routes Using the Laravel variant we can do this modification by adding the following code: ```php From c077e4d8774a476f6f77d0efd07e1f758d64038d Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:29:24 +0200 Subject: [PATCH 10/33] Fix title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 1442793480d..de2fbf1d35a 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -59,7 +59,7 @@ The GraphiQL IDE can also be found at `/graphql/graphiql`. If you need to disable it, it can be done in the configuration: -### Disable GraphiQL with Symfony +### Disabling GraphiQL with Symfony ```yaml # api/config/packages/api_platform.yaml api_platform: From 1e5733db01f555716c48fdbdb1f838d2aadedc70 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 13:29:43 +0200 Subject: [PATCH 11/33] Fix title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- core/graphql.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index de2fbf1d35a..73eb7dff2c7 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -69,7 +69,8 @@ api_platform: # ... ``` -### Disable GraphiQL with Laravel +### Disabling GraphiQL with Laravel + ```php Date: Thu, 3 Oct 2024 13:34:16 +0200 Subject: [PATCH 12/33] Fix titles and coding style --- core/extending.md | 8 ++++---- core/graphql.md | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/extending.md b/core/extending.md index e943d9c7b30..14e00f8c1c4 100644 --- a/core/extending.md +++ b/core/extending.md @@ -59,9 +59,9 @@ flowchart TB ### Symfony Access Checker Provider When using Symfony, the access checker provider is used at three different stages: -- `api_platform.state_provider.access_checker.post_validate` decorates the ValidateProvider -- `api_platform.state_provider.access_checker.post_deserialize` decorates the DeserializeProvider -- `api_platform.state_provider.access_checker` decorates the ReadProvider +- `api_platform.state_provider.access_checker.post_validate` decorates the `ValidateProvider` +- `api_platform.state_provider.access_checker.post_deserialize` decorates the `DeserializeProvider` +- `api_platform.state_provider.access_checker` decorates the `ReadProvider` ### Decoration Example @@ -78,7 +78,7 @@ use ApiPlatform\State\ProcessorInterface; final class CustomRespondProcessor implements ProcessorInterface { - public function __construct(private readonly ProcessorInterface $processor){} + public function __construct(private readonly ProcessorInterface $processor) {} public function __invoke($data, string $resourceClass, string $operationName, array $context) { diff --git a/core/graphql.md b/core/graphql.md index 73eb7dff2c7..fd8b0921eb1 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -22,11 +22,13 @@ You can now use GraphQL at the endpoint: `https://localhost:8443/graphql`. > If you used [the Symfony Variant thanks to Symfony Flex](../symfony/index.md#using-symfony-flex-and-composer-advanced-users) or the Laravel variant, URLs will be prefixed with `/api` by default. For example, the GraphQL endpoint will be: `https://localhost:8443/api/graphql`. ## Changing Location of the GraphQL Endpoint + Sometimes you may want to have the GraphQL endpoint at a different location. This can be done by manually configuring the GraphQL controller. -### Symfony Config for Routes +### Symfony Routes Using the Symfony variant we can do this modification by adding the following code: + ```yaml # api/config/routes.yaml api_graphql_entrypoint: From 0f7d85b2d7dba451a8e64069ae5aa7743eb641ea Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 3 Oct 2024 17:06:43 +0200 Subject: [PATCH 13/33] Fix wrong implementation & rm duplicate code --- core/extending.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core/extending.md b/core/extending.md index 14e00f8c1c4..98d52665c96 100644 --- a/core/extending.md +++ b/core/extending.md @@ -80,12 +80,12 @@ final class CustomRespondProcessor implements ProcessorInterface { public function __construct(private readonly ProcessorInterface $processor) {} - public function __invoke($data, string $resourceClass, string $operationName, array $context) + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): void { // You can add pre-write code here. - // Call the decorated write stage (this syntax calls the __invoke method). - $writtenObject = ($this->processor)($data, $resourceClass, $operationName, $context); + // Call the decorated processor's process method. + $this->processor->process($data, $operation, $uriVariables, $context); // You can add post-write code here. @@ -139,11 +139,7 @@ class AppServiceProvider extends ServiceProvider { public function register(): void { - $this->app->singleton(CustomRespondProcessor::class, function (Application $app) { - return new CustomRespondProcessor(); - }); - - $this->app->extend(RespondProcessor::class, function (RespondProcessor $respondProcessor, Application $app) { + $this->app->extend(RespondProcessor::class, function (RespondProcessor $respondProcessor) { return new CustomRespondProcessor($respondProcessor); }); } From 6d8fa0f0c32a622dd6410ec6c50cfa4a509aeef9 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:01:22 +0200 Subject: [PATCH 14/33] Fix spelling and class rendering Co-authored-by: Antoine Bluchet --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 98d52665c96..5a7a05c9d59 100644 --- a/core/extending.md +++ b/core/extending.md @@ -94,7 +94,7 @@ final class CustomRespondProcessor implements ProcessorInterface } ``` -Now you should decorate the RespondProcessor with the CustomRespondProcessor using Symfony or Laravel: +Now decorate the `RespondProcessor` with the `CustomRespondProcessor` using Symfony or Laravel: ### Decorating the RespondProcessor with Symfony From 4881372a38f84b9f34741d3f736b7acecca9d8fe Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:02:01 +0200 Subject: [PATCH 15/33] Fix title with a better title name Co-authored-by: Antoine Bluchet --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 5a7a05c9d59..257ffa53d10 100644 --- a/core/extending.md +++ b/core/extending.md @@ -96,7 +96,7 @@ final class CustomRespondProcessor implements ProcessorInterface Now decorate the `RespondProcessor` with the `CustomRespondProcessor` using Symfony or Laravel: -### Decorating the RespondProcessor with Symfony +### Symfony Processor Decoration With Symfony you can simply do that by adding the `#[AsDecorator]` attribute as following: From 8817275f1c634594e51ef433b479ef9e58de174b Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:02:28 +0200 Subject: [PATCH 16/33] Fix title with a better title name Co-authored-by: Antoine Bluchet --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 257ffa53d10..5b72502116d 100644 --- a/core/extending.md +++ b/core/extending.md @@ -124,7 +124,7 @@ services: And that's it! -### Decorating the RespondProcessor with Laravel +### Laravel Processor Decoration ```php Date: Fri, 4 Oct 2024 10:03:20 +0200 Subject: [PATCH 17/33] Fix remove unused method Co-authored-by: Antoine Bluchet --- core/extending.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/extending.md b/core/extending.md index 5b72502116d..4f38420c1b5 100644 --- a/core/extending.md +++ b/core/extending.md @@ -143,9 +143,5 @@ class AppServiceProvider extends ServiceProvider return new CustomRespondProcessor($respondProcessor); }); } - - public function boot(): void - { - } } ``` From 242077363984196d9171123a2126e2ed1d46e637 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:03:39 +0200 Subject: [PATCH 18/33] Fix remove unused method Co-authored-by: Antoine Bluchet --- core/graphql.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index fd8b0921eb1..322d4e33551 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2285,10 +2285,6 @@ class AppServiceProvider extends ServiceProvider return new ErrorHandlerDecorated($errorHandler); }); } - - public function boot(): void - { - } } ``` From b8e244ec6069d9063761cc76d1bb954036b537fd Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:04:34 +0200 Subject: [PATCH 19/33] Fix remove unused method Co-authored-by: Antoine Bluchet --- core/graphql.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index 322d4e33551..07bbcdd3978 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2637,10 +2637,6 @@ class AppServiceProvider extends ServiceProvider { $this->app->tag([DateTimeType::class], TypeInterface::class); } - - public function boot(): void - { - } } ``` From c97e01035b8e2caba920b523d4c99717a5b9bb1a Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:05:52 +0200 Subject: [PATCH 20/33] Fix by rephrasing not available commands message Co-authored-by: Antoine Bluchet --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 07bbcdd3978..0732639a8c1 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2764,7 +2764,7 @@ final class BookContextBuilder implements SerializerContextBuilderInterface ## Export the Schema in SDL > [!WARNING] -> These commands are only available for API Platform with Symfony! +> This command is not yet available with Laravel, you're welcome to contribute [on Github](github.com/api-platform/core) You may need to export your schema in SDL (Schema Definition Language) to import it in some tools. From 48c5c961a231bec3102f2e20fb479af7e4120478 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:06:48 +0200 Subject: [PATCH 21/33] Fix better explanations to enable GraphQL Co-authored-by: Antoine Bluchet --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 0732639a8c1..556b5edfbf1 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -10,7 +10,7 @@ Once enabled, you have nothing to do: your schema describing your API is automat ## Enabling GraphQL -To enable GraphQL and its IDE (GraphiQL and GraphQL Playground) in your API, simply require the [API Platform GraphQL](https://github.com/api-platform/graphql) package using Composer: +To enable GraphQL and its IDE (GraphiQL and GraphQL Playground) in your API, simply require the `api-platform/graphql` package using Composer: ```console composer require api-platform/graphql From 587627578cc0a7fc1b40c823bce2317903487b21 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:08:33 +0200 Subject: [PATCH 22/33] Fix remove unused declaration in the Laravel container Co-authored-by: Antoine Bluchet --- core/graphql.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index 556b5edfbf1..3e83ab640d3 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2277,10 +2277,6 @@ class AppServiceProvider extends ServiceProvider { public function register(): void { - $this->app->singleton(ErrorHandlerDecorated::class, function (Application $app) { - return new ErrorHandlerDecorated(); - }); - $this->app->extend(ErrorHandler::class, function (ErrorHandler $errorHandler, Application $app) { return new ErrorHandlerDecorated($errorHandler); }); From 5faa513c6425d432a5eea5caf94279339ae95e57 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:14:54 +0200 Subject: [PATCH 23/33] Fix typo Co-authored-by: Alan Poulain --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 4f38420c1b5..384d60dade4 100644 --- a/core/extending.md +++ b/core/extending.md @@ -39,7 +39,7 @@ To replace existing API Platform services with your decorators, [check out how t ## System Providers and Processors -The system is based on a workflow composed of **state providers** and **state processors** +The system is based on a workflow composed of **state providers** and **state processors**. The schema below describes them: From 52903a3959071500b2c7d3731c7fc216b684b812 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:15:40 +0200 Subject: [PATCH 24/33] Fix typo Co-authored-by: Alan Poulain --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 384d60dade4..399bff6ba90 100644 --- a/core/extending.md +++ b/core/extending.md @@ -105,7 +105,7 @@ namespace App\State; use ApiPlatform\State\ProcessorInterface; -#[AsDecorator(decorates: 'api_platform.state.processor.respond_processor',)] +#[AsDecorator(decorates: 'api_platform.state.processor.respond_processor')] final class CustomRespondProcessor implements ProcessorInterface { // ... From 6b6e7a44d8bca1c6d3980276c3d8a8c822ae18d4 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:16:12 +0200 Subject: [PATCH 25/33] Fix spelling Co-authored-by: Alan Poulain --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 3e83ab640d3..a82145c0ea4 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -416,7 +416,7 @@ final class BookCollectionResolver implements QueryCollectionResolverInterface If you use autoconfiguration (the default Symfony configuration) in your application, then you are done! -Else, you need to tag your resolver like this if you using Symfony without autoconfiguration : +Else, you need to tag your resolver like this if you are using Symfony without autoconfiguration : ```yaml # api/config/services.yaml From fe8941cfb121bce63c20056b2cba399e524367d7 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:16:36 +0200 Subject: [PATCH 26/33] Fix typo Co-authored-by: Alan Poulain --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index a82145c0ea4..f25688b7b9d 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2305,7 +2305,7 @@ It's the case for a `HttpException` for which the `status` entry will be added u #### Custom Exception Normalizer > [!CAUTION] -> Works only for API Platform with Symfony, +> Works only for API Platform with Symfony If you want to add more specific behaviors depending on the exception or if you want to change the behavior of the built-in ones, you can do so by creating your own normalizer. From b7b20fd680d912d18f2f3e7f60257cda2a1b86fd Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:17:18 +0200 Subject: [PATCH 27/33] Fix typo Co-authored-by: Alan Poulain --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index f25688b7b9d..c6e91c7831d 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -868,7 +868,7 @@ For instance, you could receive a JSON payload like this: ### Subscriptions Cache Internally, API Platform stores the subscriptions in a cache, using the [Symfony Cache](https://symfony.com/doc/current/cache.html) if you're using the Symfony variant -or ÆPI Platform uses [Laravel cache](https://laravel.com/docs/cache) if you're use the Laravel variant. +or API Platform uses [Laravel cache](https://laravel.com/docs/cache) if you're using the Laravel variant. The cache is named `api_platform.graphql.cache.subscription` and the subscription keys are generated from the subscription payload by using a SHA-256 hash. From f451b875c44b2060ef3552c098d16f0b6663e416 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 10:18:04 +0200 Subject: [PATCH 28/33] Fix missing var assignation Co-authored-by: Alan Poulain --- core/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index 399bff6ba90..a417f120b4e 100644 --- a/core/extending.md +++ b/core/extending.md @@ -85,7 +85,7 @@ final class CustomRespondProcessor implements ProcessorInterface // You can add pre-write code here. // Call the decorated processor's process method. - $this->processor->process($data, $operation, $uriVariables, $context); + $writtenObject = $this->processor->process($data, $operation, $uriVariables, $context); // You can add post-write code here. From a7ef50052d3ee2cc0ae2dc6038693ac2b193be54 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 11:33:25 +0200 Subject: [PATCH 29/33] Add recommendation for using system providers and processors --- core/events.md | 1 + 1 file changed, 1 insertion(+) diff --git a/core/events.md b/core/events.md index efa80706345..ee5319f7c83 100644 --- a/core/events.md +++ b/core/events.md @@ -7,6 +7,7 @@ > [!NOTE] > Using Kernel event with API Platform should be mostly limited to tweaking the generated HTTP response. Also, GraphQL is **not supported**. +> We recommend to use [System providers and processors](extending.md#system-providers-and-processors) to extend API Platform internals. API Platform Core implements the [Action-Domain-Responder](https://github.com/pmjones/adr) pattern. This implementation is covered in depth in the [Creating custom operations and controllers](operations.md#creating-custom-operations-and-controllers) From a713745e259ea68bac3e5ee04dabfe6b2182ed06 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 11:34:04 +0200 Subject: [PATCH 30/33] Add GraphQL state provider access checker notes & cleanup --- core/extending.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/extending.md b/core/extending.md index a417f120b4e..47f37af53e9 100644 --- a/core/extending.md +++ b/core/extending.md @@ -63,6 +63,10 @@ When using Symfony, the access checker provider is used at three different stage - `api_platform.state_provider.access_checker.post_deserialize` decorates the `DeserializeProvider` - `api_platform.state_provider.access_checker` decorates the `ReadProvider` +> [!NOTE] +> For graphql use: `api_platform.graphql.state_provider.access_checker.post_deserialize`, +> `api_platform.graphql.state_provider.access_checker.post_validate`, `api_platform.graphql.state_provider.validate` and +> `api_platform.graphql.state_provider.access_checker.after_resolver` ### Decoration Example @@ -132,7 +136,6 @@ namespace App\Providers; use App\State\CustomRespondProcessor; use ApiPlatform\State\Processor\RespondProcessor; -use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider From ace7aeb86212961d2b0cbe2c1a3b4faa718043e3 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 11:35:21 +0200 Subject: [PATCH 31/33] Completes GraphQL doc for Laravel support & clarified some points reviewed --- core/graphql.md | 120 +++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index c6e91c7831d..99f3e8a5f9c 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -75,7 +75,7 @@ api_platform: ```php [ @@ -133,18 +133,8 @@ api_platform: ### Disable GraphQL Playground with Laravel -```php - [ - 'graphql_playground' => [ - 'enabled' => false, - ] - ], -]; -``` +> [!WARNING] +> This is not yet available with Laravel, you're welcome to contribute [on Github](github.com/api-platform/core) ### Add another Location for GraphQL Playground You can add a different location besides `/graphql/graphql_playground`. @@ -191,7 +181,7 @@ api_platform: ```php [ @@ -215,7 +205,7 @@ api_platform: ### Laravel config to disable default IDE ```php [ @@ -245,7 +235,7 @@ If you need to disable it, it can be done in the configuration: ```php [ @@ -273,7 +263,7 @@ api_platform: ```php [ @@ -885,7 +875,7 @@ See the [Extending API Platform](extending.md) documentation for more informatio ### Disabling system providers and processors -If you need to, you can disable some states providers and state processors done by the resolvers, for instance if you don't want your data to be validated. +If you need to, you can disable some states providers and state processors, for instance if you don't want your data to be validated. The following table lists the system states providers and states processors you can disable in your resource configuration. @@ -1437,7 +1427,7 @@ api_platform: ```php [ @@ -2270,14 +2260,13 @@ namespace App\Providers; use App\Error\ErrorHandler as ErrorHandlerDecorated; use ApiPlatform\GraphQl\Error\ErrorHandler; -use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function register(): void { - $this->app->extend(ErrorHandler::class, function (ErrorHandler $errorHandler, Application $app) { + $this->app->extend(ErrorHandler::class, function (ErrorHandler $errorHandler) { return new ErrorHandlerDecorated($errorHandler); }); } @@ -2489,7 +2478,7 @@ In this case, your query will be: ```php [ @@ -2642,14 +2631,13 @@ To use it please [modify the extracted types](#modify-the-extracted-types) or us ## Modify the Extracted Types -> [!WARNING] -> This part is only supported for API Platform with Symfony - The GraphQL schema and its types are extracted from your resources. In some cases, you would want to modify the extracted types for instance to use your custom ones. To do so, you need to decorate the `api_platform.graphql.type_converter` service: +### Symfony TypeConverter Decoration + ```yaml # api/config/services.yaml services: @@ -2658,7 +2646,29 @@ services: decorates: api_platform.graphql.type_converter ``` -Your class needs to look like this: +### Laravel TypeConverter Decoration + +```php +app->extend(TypeConverterInterface::class, function (TypeConverterInterface $typeConverter) { + return new TypeConverter($typeConverter); + }); + } +} +``` + +Then, your class needs to look like this: ```php defaultTypeConverter = $defaultTypeConverter; - } + public function __construct(private readonly TypeConverterInterface $defaultTypeConverter) {} public function convertType(Type $type, bool $input, Operation $rootOperation, string $resourceClass, string $rootResource, ?string $property, int $depth) { @@ -2711,10 +2717,7 @@ if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType() All `DateTimeInterface` properties will have the `DateTime` type in this example. -## Changing the Serialization Context Dynamically (only for Symfony) - -> [!WARNING] -> This part is only supported for API Platform with Symfony +## Changing the Serialization Context Dynamically [As REST](serialization.md#changing-the-serialization-context-dynamically), it's possible to add dynamically a (de)serialization group when resolving a query or a mutation. @@ -2724,6 +2727,8 @@ The service is `api_platform.graphql.serializer.context_builder` and the method The decorator could be like this: +### Symfony Serialization Context Decoration + ```php decorated = $decorated; - $this->authorizationChecker = $authorizationChecker; + $context = $this->decorated->create($resourceClass, $operationName, $resolverContext, $normalization); + $resourceClass = $context['resource_class'] ?? null; + + if ($resourceClass === Book::class && isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && false === $normalization) { + $context['groups'][] = 'admin:input'; + } + + return $context; } +} +``` + +### Laravel Serialization Context Decoration +```php +decorated->create($resourceClass, $operationName, $resolverContext, $normalization); $resourceClass = $context['resource_class'] ?? null; - if ($resourceClass === Book::class && isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && false === $normalization) { + if ($resourceClass === Book::class && isset($context['groups']) && $this->isAdmin() && !$normalization) { $context['groups'][] = 'admin:input'; } return $context; } + + private function isAdmin(): bool + { + $user = Auth::user(); + + return $user && $user->role === 'admin'; + } } ``` @@ -2905,7 +2941,7 @@ api_platform: #### Modifying allowed formats with Laravel ```php [ From a70e3b76fbfbe9550643f4edf54925c78073f137 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Fri, 4 Oct 2024 12:31:25 +0200 Subject: [PATCH 32/33] Fix string syntax error Co-authored-by: Alan Poulain --- core/graphql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/graphql.md b/core/graphql.md index 99f3e8a5f9c..dd62d5eaa0b 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2482,7 +2482,7 @@ In this case, your query will be: return [ // .... 'graphql' => [ - 'nesting_separator' => __ + 'nesting_separator' => '__' ], ]; ``` From 07f6032000b8aa83e53b8c1edf8fb33b83ed3f9f Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Fri, 4 Oct 2024 14:59:46 +0200 Subject: [PATCH 33/33] Apply suggestions from code review --- core/graphql.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/graphql.md b/core/graphql.md index dd62d5eaa0b..b3125977e24 100644 --- a/core/graphql.md +++ b/core/graphql.md @@ -2293,9 +2293,6 @@ It's the case for a `HttpException` for which the `status` entry will be added u #### Custom Exception Normalizer -> [!CAUTION] -> Works only for API Platform with Symfony - If you want to add more specific behaviors depending on the exception or if you want to change the behavior of the built-in ones, you can do so by creating your own normalizer. Please follow the [Symfony documentation to create a custom normalizer](https://symfony.com/doc/current/serializer/custom_normalizer.html).