Skip to content

Commit feb16c3

Browse files
committed
Write resolvers.md content
1 parent 2218c1e commit feb16c3

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

doc/resolvers.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Field Resolvers
2+
3+
GraphQL schemas define types with named fields, and each of those fields may
4+
take arguments which alter the behavior of that field. You can think of
5+
`fields` much like methods on an object instance in OOP (Object Oriented
6+
Programming). Each field is implemented using a `resolver`, which may
7+
recursively invoke additional `resolvers` for fields of the resulting objects,
8+
e.g.:
9+
```graphql
10+
query {
11+
foo(id: "bar") {
12+
baz
13+
}
14+
}
15+
```
16+
17+
This query would invoke the `resolver` for the `foo field` on the top-level
18+
`query` object, passing it the string `"bar"` as the `id` argument. Then it
19+
would invoke the `resolver` for the `baz` field on the result of the `foo
20+
field resolver`.
21+
22+
## Top-level Resolvers
23+
24+
The `schema` type in GraphQL defines the types for top-level operation types.
25+
By convention, these are often named after the operation type, although you
26+
could give them different names:
27+
```graphql
28+
schema {
29+
query: Query
30+
mutation: Mutation
31+
subscription: Subscription
32+
}
33+
```
34+
35+
Executing a query or mutation starts by calling `Request::resolve` from [GraphQLService.h](../include/graphqlservice/GraphQLService.h):
36+
```cpp
37+
std::future<response::Value> resolve(const std::shared_ptr<RequestState>& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const;
38+
```
39+
By default, the `std::future` results are resolved on-demand but synchronously,
40+
using `std::launch::deferred` with the `std::async` function. You can also use
41+
an override of `Request::resolve` which lets you substitute the
42+
`std::launch::async` option to begin executing the query on multiple threads
43+
in parallel:
44+
```cpp
45+
std::future<response::Value> resolve(std::launch launch, const std::shared_ptr<RequestState>& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const;
46+
```
47+
48+
### `graphql::service::Request` and `graphql::<schema>::Operations`
49+
50+
Anywhere in the documentation where it mentions `graphql::service::Request`
51+
methods, the concrete type will actually be `graphql::<schema>::Operations`.
52+
This `class` is defined by `schemagen` and inherits from
53+
`graphql::service::Request`. It links the top-level objects for the custom
54+
schema to the `resolve` methods on its base class. See
55+
`graphql::today::Operations` in [TodaySchema.h](../samples/separate/TodaySchema.h)
56+
for an example.
57+
58+
## Generated Service Schema
59+
60+
The `schemagen` tool generates C++ types in the `graphql::<schema>::object`
61+
namespace with `resolveField` methods for each `field` which parse the
62+
arguments from the `query` and automatically dispatch the call to a `getField`
63+
virtual method to retrieve the `field` result. On `object` types, it will also
64+
recursively call the `resolvers` for each of the `fields` in the nested
65+
`SelectionSet`. See for example the generated
66+
`graphql::today::object::Appointment` object from the `today` sample in
67+
[AppointmentObject.h](../samples/separate/AppointmentObject.h).
68+
```cpp
69+
std::future<response::Value> resolveId(service::ResolverParams&& params);
70+
```
71+
In this example, the `resolveId` method invokes `getId`:
72+
```cpp
73+
virtual service::FieldResult<response::IdType> getId(service::FieldParams&& params) const override;
74+
```
75+
76+
There are also a couple of interesting quirks in this example:
77+
1. The `Appointment object` implements and inherits from the `Node interface`,
78+
which already declared `getId` as a pure-virtual method. That's what the
79+
`override` keyword refers to.
80+
2. This schema was generated with default stub implementations (without the
81+
`schemagen --no-stubs` parameter) which speed up initial development with NYI
82+
(Not Yet Implemented) stubs. With that parameter, there would be no
83+
declaration of `Appointment::getId` since it would inherit a pure-virtual
84+
declaration and the implementer would need to define an override on the
85+
concrete implementation of `graphql::today::object::Appointment`. The NYI stub
86+
will throw a `std::runtime_error`, which the `resolver` converts into an entry
87+
in the `response errors` collection:
88+
```cpp
89+
throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex");
90+
```

0 commit comments

Comments
 (0)