Skip to content

Add advanced queries and policies guides to GraphQL docs #2634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docusaurus/docs/cms/api/graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ The GraphQL API does not support media upload. Use the [REST API `POST /upload`
The GraphQL API exposes documents using only the `documentId` field. The previous numeric `id` is no longer available here, although it is still returned by the REST API for backward compatibility (see [breaking change](/cms/migration/v4-to-v5/breaking-changes/use-document-id) for details).
:::


## Queries

Queries in GraphQL are used to fetch data without modifying it.
Expand Down Expand Up @@ -1111,3 +1110,12 @@ mutation DeleteRestaurant($documentId: ID!, $locale: I18NLocaleCode) {
}
}
```

## Advanced use cases

Click on the following cards for short guides on more advanced use cases leveraging the GraphQL API and Strapi features:

<CustomDocCardsWrapper>
<CustomDocCard emoji="🖼️" title="Advanced queries" description="View examples of multi-level queries and custom resolver chains for the GraphQL API." link="/cms/api/graphql/advanced-queries" />
<CustomDocCard emoji="🖼️" title="Advanced policies" description="View examples of advanced policies such as conditional visibility and group membership for the GraphQL API." link="/cms/api/graphql/advanced-policies" />
</CustomDocCardsWrapper>
64 changes: 64 additions & 0 deletions docusaurus/docs/cms/api/graphql/advanced-policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Advanced policies for GraphQL
displayed_sidebar: cmsSidebar
tags:
- GraphQL API
- policies
---

# Advanced policies for the GraphQL API

Requests sent to the [GraphQL API](/cms/api/graphql) pass through Strapi's [middlewares](/cms/backend-customization/middlewares.md) and [policies](/cms/backend-customization/policies.md) system. Policies can be attached to resolvers to implement complex authorization rules, as shown in the present short guide.

For additional information on GraphQL policies, please refer to the [GraphQL plugin configuration](/cms/plugins/graphql#extending-the-schema) documentation.

## Conditional visibility

To limit the number of returned entries for unauthenticated users you can write a policy that modifies resolver arguments:

```ts title="/src/policies/limit-public-results.ts"
export default async (policyContext, config, { strapi }) => {
const { state, args } = policyContext;

if (!state.user) {
args.limit = 4; // only return 4 results for public
}

return true;
};
```

Register the policy in `/config/policies.ts` and apply it to a resolver:

```ts title="/config/policies.ts"
export default {
'api::restaurant.restaurant': {
find: [ 'global::limit-public-results' ],
},
};
```

## Group membership

Policies can access `policyContext.state.user` to check group membership, as in the following example:

```ts title="/src/policies/is-group-member.ts"
export default async ({ state }, config, { strapi }) => {
const userGroups = await strapi.query('plugin::users-permissions.group').findMany({
where: { users: { id: state.user.id } },
});
return userGroups.some(g => g.name === config.group);
};
```

Use the policy with the following configuration:

```ts title="/config/policies.ts"
export default {
'api::restaurant.restaurant': {
find: [{ name: 'global::is-group-member', config: { group: 'editors' } }],
},
};
```

With this setup the resolver only returns results if the authenticated user belongs to the `editors` group.
52 changes: 52 additions & 0 deletions docusaurus/docs/cms/api/graphql/advanced-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Advanced queries for GraphQL
displayed_sidebar: cmsSidebar
tags:
- GraphQL API
---

# Advanced queries for the GraphQL API

Strapi's [GraphQL API](/cms/api/graphql) resolves many queries automatically, but complex data access can require deeper relation fetching or chaining resolvers. The present short guide explains how to handle such advanced scenarios.

For additional information, please refer to the [GraphQL customization](/cms/plugins/graphql#extending-the-schema) documentation.

## Multi-level queries

Use nested selection sets to fetch relations several levels deep, as in the following example:

```graphql
{
restaurants {
documentId
name
categories {
documentId
name
parent {
documentId
name
}
}
}
}
```

The GraphQL plugin automatically resolves nested relations. If you need to apply custom logic at a specific level, create a custom resolver for that field.

## Resolver chains

Custom resolvers can call other resolvers to reuse existing logic. A common pattern is to resolve permissions or context data in a parent resolver and pass it down to child resolvers, as in the following example:

```js title="/src/api/restaurant/resolvers/restaurant.ts"
export default {
Query: {
restaurants: async (parent, args, ctx) => {
const documents = await strapi.documents('api::restaurant.restaurant').findMany(args);
return documents.map(doc => ctx.request.graphql.resolve('Restaurant', doc));
},
},
};
```

In this example the parent resolver fetches restaurants using the [Document Service API](/cms/api/document-service), then delegates to the generated `Restaurant` resolver provided by the plugin so default behavior such as field selection still applies.
8 changes: 8 additions & 0 deletions docusaurus/docs/cms/plugins/graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,10 @@ When [extending the GraphQL schema](#extending-the-schema), the `resolversConfig
* [policies with the `policies`](#policies) key
* and [middlewares with the `middlewares`](#middlewares) key

:::tip
The [advanced queries](/cms/api/graphql/advanced-queries) guide might contain additional information suitable for your use case, including multi-level queries and custom resolvers examples.
:::

###### Authorization configuration

By default, the authorization of a GraphQL request is handled by the registered authorization strategy that can be either [API token](/cms/features/api-tokens) or through the [Users & Permissions plugin](#usage-with-the-users--permissions-plugin). The Users & Permissions plugin offers a more granular control.
Expand Down Expand Up @@ -877,6 +881,10 @@ export default {

</details>

:::tip
The [advanced policies](/cms/api/graphql/advanced-policies) guide might contain additional information suitable for your use case.
:::

###### Middlewares

[Middlewares](/cms/backend-customization/middlewares) can be applied to a GraphQL resolver through the `resolversConfig.[MyResolverName].middlewares` key. The only difference between the GraphQL and REST implementations is that the `config` key becomes `options`.
Expand Down