Skip to content

Commit

Permalink
Refactor GraphQL & extending documentations for clarity and accuracy
Browse files Browse the repository at this point in the history
Updated terminology from "stages" to "providers and processors" for better clarity. Removed redundant sections to streamline information on custom mutations and configuration examples.
  • Loading branch information
vinceAmstoutz committed Oct 3, 2024
1 parent 060b4a6 commit 8495af2
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 173 deletions.
3 changes: 2 additions & 1 deletion core/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
namespace App\State;
Expand Down
182 changes: 10 additions & 172 deletions core/graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,12 @@ final class BookCollectionResolver implements QueryCollectionResolverInterface
}
```

### Custom Queries config for Symfony
### Custom Queries config for Symfony

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 :


```yaml
# api/config/services.yaml
services:
Expand Down Expand Up @@ -633,8 +632,8 @@ They are following the GraphQL type system.
If you don't define the `args` property, it will be the default ones (for example `id` for an item).
You can also use the `extraArgs` property if you want to add more arguments than the generated ones.

If you don't want API Platform to retrieve the item for you, disable the `read` stage like in `withDefaultArgsNotRetrievedQuery`.
Some other stages [can be disabled](#disabling-resolver-stages).
If you don't want API Platform to retrieve the item for you, disable the `read` provider.
Some other providers and processors [can be disabled](#disabling-system-providers-and-processors).
Another option would be to make sure there is no `id` argument.
This is the case for `notRetrievedQuery` (empty args).
Conversely, if you need to add custom arguments, make sure `id` is added among the arguments if you need the item to be retrieved automatically.
Expand Down Expand Up @@ -737,145 +736,17 @@ final class BookMutationResolver implements MutationResolverInterface
```

As you can see, depending on how you configure your custom mutation in the resource, the item is retrieved or not.
For instance, if you don't set an `id` argument or if you disable the `read` or the `deserialize` stage (other stages [can also be disabled](#disabling-resolver-stages)),
For instance, if you don't set an `id` argument or if you disable the `read` or the `deserialize` providers (other state providers and state processors [can also be disabled](#disabling-system-providers-and-processors)),
the received item will be `null`.

Likewise, if you don't want your item to be persisted by API Platform,
you can return `null` instead of the mutated item (be careful: the response will also be `null`) or disable the `write` stage.
you can return `null` instead of the mutated item (be careful: the response will also be `null`) or disable the `write` provider.

Don't forget the resolver is a service and you can inject the dependencies you want.

If you don't use autoconfiguration, add the tag `api_platform.graphql.mutation_resolver` to the resolver service.
If you're using Laravel, don't forget to tag the resolver service with the `ApiPlatform\GraphQl\Resolver\MutationResolverInterface`.

Now in your resource:

<code-selector>

```php
<?php
// api/src/Entity/Book.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GraphQl\DeleteMutation;
use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\GraphQl\QueryCollection;
use App\Resolver\BookMutationResolver;
#[ApiResource(
graphQlOperations: [
new Query(),
new QueryCollection(),
new Mutation(name: 'create'),
new Mutation(name: 'update'),
new DeleteMutation(name: 'delete'),
new Mutation(
name: 'mutation',
resolver: BookMutationResolver::class,
extraArgs: ['id' => ['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
<!--The XML syntax is only supported for Symfony-->
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
https://api-platform.com/schema/metadata/resources-3.0.xsd">
<resource class="App\Entity\Book">
<graphQlOperations>
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Query" />
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\QueryCollection" />
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="create" />
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="update" />
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="delete" />
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="mutation" resolver="App\Resolver\BookMutationResolver">
<extraArgs>
<arg id="id">
<values>
<value name="type">ID!</value>
</values>
</arg>
</extraArgs>
</graphQlOperation>
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="withCustomArgsMutation" resolver="App\Resolver\BookMutationResolver">
<args>
<arg id="sendMail">
<values>
<value name="type">Boolean!</value>
<value name="description">Send a mail?</value>
</values>
</arg>
</args>
</graphQlOperation>
<graphQlOperation class="ApiPlatform\Metadata\GraphQl\Mutation" name="disabledStagesMutation" resolver="App\Resolver\BookMutationResolver" deserialize="false" write="false" />
</graphQlOperations>
</resource>
</resources>
```

</code-selector>

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).
Expand All @@ -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.
Expand Down Expand Up @@ -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 |
|----------------------------|--------|---------|-------------------------------------------|
Expand Down Expand Up @@ -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!

Expand All @@ -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:

Expand Down Expand Up @@ -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!
Expand Down

0 comments on commit 8495af2

Please sign in to comment.