Skip to content

Commit bd76a8e

Browse files
authored
docs: document rp.beforeQuery (#372)
1 parent c2449a9 commit bd76a8e

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ This is a plugin for [graphql-compose](https://github.com/graphql-compose/graphq
4949
- [How to build nesting/relations?](#how-to-build-nestingrelations)
5050
- [Reusing the same mongoose Schema in embedded object fields](#reusing-the-same-mongoose-schema-in-embedded-object-fields)
5151
- [Access and modify mongoose doc before save](#access-and-modify-mongoose-doc-before-save)
52+
- [How can I restrict access to certain fields or documents?](#how-can-i-restrict-access-to-certain-fields-or-documents)
5253
- [How can I push/pop or add/remove values to arrays?](#how-can-i-pushpop-or-addremove-values-to-arrays)
5354
- [Is it possible to use several schemas?](#is-it-possible-to-use-several-schemas)
5455
- [Embedded documents has `_id` field and you don't need it?](#embedded-documents-has-_id-field-and-you-dont-need-it)
@@ -1046,6 +1047,65 @@ schemaComposer.Mutation.addFields({
10461047
});
10471048
```
10481049

1050+
### How can I restrict access to certain fields or documents?
1051+
1052+
This library allows modifying the query before it is executed using the `beforeQuery` hook. This lets us prevent certain fields or documents from being read. Here's an example of restricting access to specific fields:
1053+
1054+
```ts
1055+
schemaComposer.Query.addFields({
1056+
userOne: UserTC.mongooseResolvers.findOne().wrapResolve((next) => (rp) => {
1057+
const { role } = rp.context;
1058+
1059+
rp.beforeQuery = (query: Query<unknown, unknown>) => {
1060+
if (role === 'admin') {
1061+
// Don't change the projection and still allow all fields to be read
1062+
} else if (role === 'moderator') {
1063+
// Only allow the name, age, and gender fields to be read
1064+
query.projection({ name: 1, age: 1, gender: 1 });
1065+
} else if (role === 'public') {
1066+
// Only allow the name field to be read
1067+
query.projection({ name: 1 });
1068+
}
1069+
};
1070+
1071+
return next(rp);
1072+
}),
1073+
});
1074+
```
1075+
1076+
Note that fields that are sometimes restricted should not be marked as required in the mongoose schema. Otherwise, when you query them you will get a "Cannot return null for non-nullable field" error because the database query didn't return a value for the field.
1077+
1078+
You can also use `beforeQuery` to hide certain documents from the query. Here's an example:
1079+
1080+
```ts
1081+
schemaComposer.Query.addFields({
1082+
postMany: PostTC.mongooseResolvers.findMany().wrapResolve((next) => (rp) => {
1083+
const { userId } = rp.context;
1084+
1085+
rp.beforeQuery = (query: Query<unknown, unknown>) => {
1086+
// Only allow users to see their own posts
1087+
query.where('authorId', userId);
1088+
};
1089+
1090+
return next(rp);
1091+
}),
1092+
});
1093+
```
1094+
1095+
Both of these examples require putting extra data in the resolver context. Here's how to attach context data in Apollo Server:
1096+
1097+
```ts
1098+
const server = new ApolloServer({
1099+
schema: schemaComposer.buildSchema(),
1100+
context() {
1101+
// This role should actually come from a JWT or something
1102+
return { role: 'admin' };
1103+
},
1104+
});
1105+
```
1106+
1107+
Other GraphQL servers are likely similar.
1108+
10491109
### How can I push/pop or add/remove values to arrays?
10501110

10511111
The default resolvers, by design, will replace (overwrite) any supplied array object when using e.g. `updateById`. If you want to push or pop a value in an array you can use a custom resolver with a native MongoDB call.

0 commit comments

Comments
 (0)