Assuming there is an already existing query CartQuery
, which has GraphQL fields defined in the function getAddProductToCartMutation
, imagine you want to add additional customResults
field with customErrors
subfields:
The Field
object returns a Field
when addArgument
or addField
is called on it, so all that you need to do actually is call the original getAddProductToCartMutation
function, which will return a field, and add a field to it.
<aside>
➡️ How to call functions with plugins?
According to plugin docs, since the function we’re plugging into is inside a class, we need a member-function
plugin.
</aside>
The initial idea might be to re-create all fields and return the new fields in function result like so:
const getCustomResultsField = () => {
return new Field('customResults')
.addField('customErrors');
}
export default {
'Query/Cart/Query': {
'member-function': {
getAddProductToCartMutation: (args, callback) => {
return new Field('addProductsToCart')
.addArgument('cartId', 'String!', cartId)
.addArgument('cartItems', '[CartItemInput!]!', cartItems)
.addField(this._getUserErrorsField())
// vvv new Custom field
.addField(this.getCustomResultsField());
}
}
}
}
But, remember that you should not overwrite functions logics with plugins, always extend them.
<aside>
ℹ️ Ideally, you should consider the result of render
function execution as a black box and operate on it assuming it returns a valid type, in our case ReactElement
.
</aside>
So let’s replace the original function’s result with callback(...args)
, which is the original function being called:
const getCustomResultsField = () => {
return new Field('customResults')
.addField('customErrors');
}
export default {
'Query/Cart/Query': {
'member-function': {
getAddProductToCartMutation: (args, callback) => {
return callback(...args)
.addField(this.getCustomResultsField());
}
}
}
}
This is it! But, there are a few things to consider. You need to refactor the plugin itself into a separate function, and getCustomResultsField
should not be defined inside plugin**, it should be defined inside src/query
folder as a separate class** (To keep up with consistency of core project).
class CartCustomResultsQuery {
getCustomResultsField() {
return new Field('customResults')
.addField('customErrors');
}
}
export default new CartCustomResultsQuery();
And finally, refactor the plugin to a separate function, so you improve the readability and maintenance of the code:
import CartCustomResultsQuery from '../query/CartCustomResults.query';
const addCustomResultsFieldToCartMutationFields = (args, callback) => {
return callback(...args)
.addField(CartCustomResultsQuery.getCustomResultsField());
};
export default {
'Query/Cart/Query': {
'member-function': {
getAddProductToCartMutation: addCustomResultsFieldToCartMutationFields
}
}
}
/plugin/ProductListQuery.plugin.js
In this example, additional field dimensions
is added to existing _getCartProductField
.
Let’s say you want to add multiple fields called customRating, customReviewCounts, customReactions
into _getCartProductInterfaceFields
to extend a product data with more fields.
The original source code:
The intended modification:
To achieve this, you can plugin into _getCartProductInterfaceFields
and extend the result array with additional fields. And according to plugin docs, for that, you should use also
member-function
plugin:
const getCustomFields = () => {
return [
'customRating',
'customReviewCounts',
'customReactions'
];
}
export default {
'Query/ProductList/Query': {
'member-function': {
_getCartProductInterfaceFields: (args, callback) => {
return [
...callback(...args),
...getCustomFields()
];
}
}
}
}
Do not forget to refactor query fields into the appropriate files and to refactor plugin to a separate function for descriptiveness, readability, maintenance and consistency:
class ProductCustomResultsQuery {
getCustomFields() {
return [
'customRating',
'customReviewCounts',
'customReactions'
];
}
}
export default new ProductCustomResultsQuery();
And finally, refactoring the plugin to a separate function:
import ProductCustomResultsQuery from '../query/ProductCustomResults.query';
const addCustomFieldsToProductInterfaceFields = (args, callback) => [
...callback(...args)
.addField(ProductCustomResultsQuery.getCustomFields());
];
export default {
'Query/ProductList/Query': {
'member-function': {
_getCartProductInterfaceFields: addCustomFieldsToProductInterfaceFields
}
}
}
That’s it!
plugin/AddTurnToRatingsToProductListQuery.plugin.js
In this example, an additional field turnToRating
is added to product interface fields.