|
| 1 | +# Common Field Parameters |
| 2 | + |
| 3 | +The `resolveField` methods generated by `schemagen` will unpack any arguments |
| 4 | +matching the `schema` from the `query` and pass those to the `getField` method |
| 5 | +defined by the implementer. However, the implementer might need to inspect |
| 6 | +shared state or `directives` from the `query`, so the `resolveField` method |
| 7 | +also packs that information into a `graphql::service::FieldParams` struct and |
| 8 | +passes it to every `getField` method as the first parameter. |
| 9 | + |
| 10 | +## Details of Field Parameters |
| 11 | + |
| 12 | +The `graphql::service::FieldParams` struct is declared in [GraphQLService.h](../include/graphqlservice/GraphQLService.h): |
| 13 | +```cpp |
| 14 | +// Pass a common bundle of parameters to all of the generated Object::getField accessors in a SelectionSet |
| 15 | +struct SelectionSetParams |
| 16 | +{ |
| 17 | + // The lifetime of each of these borrowed references is guaranteed until the future returned |
| 18 | + // by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer. |
| 19 | + const std::shared_ptr<RequestState>& state; |
| 20 | + const response::Value& operationDirectives; |
| 21 | + const response::Value& fragmentDefinitionDirectives; |
| 22 | + |
| 23 | + // Fragment directives are shared for all fields in that fragment, but they aren't kept alive |
| 24 | + // after the call to the last accessor in the fragment. If you need to keep them alive longer, |
| 25 | + // you'll need to explicitly copy them into other instances of response::Value. |
| 26 | + const response::Value& fragmentSpreadDirectives; |
| 27 | + const response::Value& inlineFragmentDirectives; |
| 28 | +}; |
| 29 | + |
| 30 | +// Pass a common bundle of parameters to all of the generated Object::getField accessors. |
| 31 | +struct FieldParams : SelectionSetParams |
| 32 | +{ |
| 33 | + explicit FieldParams(const SelectionSetParams& selectionSetParams, response::Value&& directives); |
| 34 | + |
| 35 | + // Each field owns its own field-specific directives. Once the accessor returns it will be destroyed, |
| 36 | + // but you can move it into another instance of response::Value to keep it alive longer. |
| 37 | + response::Value fieldDirectives; |
| 38 | +}; |
| 39 | +``` |
| 40 | + |
| 41 | +### Request State |
| 42 | + |
| 43 | +The `SelectionSetParams::state` member is a reference to the |
| 44 | +`std::shared_ptr<graphql::service::RequestState>` parameter passed to |
| 45 | +`Request::resolve` (see [resolvers.md](./resolvers.md) for more info): |
| 46 | +```cpp |
| 47 | +// The RequestState is nullable, but if you have multiple threads processing requests and there's any |
| 48 | +// per-request state that you want to maintain throughout the request (e.g. optimizing or batching |
| 49 | +// backend requests), you can inherit from RequestState and pass it to Request::resolve to correlate the |
| 50 | +// asynchronous/recursive callbacks and accumulate state in it. |
| 51 | +struct RequestState : std::enable_shared_from_this<RequestState> |
| 52 | +{ |
| 53 | +}; |
| 54 | +``` |
| 55 | + |
| 56 | +### Scoped Directives |
| 57 | + |
| 58 | +Each of the `directives` members contains the values of the `directives` and |
| 59 | +any of their arguments which were in effect at that scope of the `query`. |
| 60 | +Implementers may inspect those values in the call to `getField` and alter their |
| 61 | +behavior based on those custom `directives`. |
| 62 | + |
| 63 | +As noted in the comments, the `fragmentSpreadDirectives` and |
| 64 | +`inlineFragmentDirectives` are borrowed `const` references, shared accross |
| 65 | +calls to multiple `getField` methods, but they will not be kept alive after |
| 66 | +the relevant `SelectionSet` has been resolved. The `fieldDirectives` member is |
| 67 | +passed by value and is not shared with other `getField` method calls, but it |
| 68 | +will not be kept alive after that call returns. It's up to the implementer to |
| 69 | +capture the values in these `directives` which they might need for asynchronous |
| 70 | +evaulation after the call to the current `getField` method has returned. |
| 71 | + |
| 72 | +The implementer does not need to capture the values of `operationDirectives` |
| 73 | +or `fragmentDefinitionDirectives` because those are kept alive until the |
| 74 | +`operation` and all of its `std::future` results are resolved. Although they |
| 75 | +passed by `const` reference, the reference should always be valid as long as |
| 76 | +there's a pending result from the `getField` call. |
| 77 | + |
| 78 | +## Related Documents |
| 79 | + |
| 80 | +1. The `getField` methods are discussed in more detail in [resolvers.md](./resolvers.md). |
| 81 | +2. Built-in and custom `directives` are discussed in [directives.md](./directives.md). |
0 commit comments