Part 2: GraphQL API
Expose product 3D models through the GraphQL API
At this point, the admin can upload and manage 3D models for each product, but these models are not yet visible to the frontend. However, before we can start implementing the frontend logic for product 3D models, we need to expose this data through an API.
GraphQL is an API language has several advantages over the conventional REST APIs β greater flexibility, better API documentation, type checking, and a simple query structure.
Scandi uses GraphQL to fetch data from the backend. For example, to fetch product data, Scandi uses the products
query:
This query already has multiple useful fields β we can query the product name, sku, price and other properties if we want. But now we want to add a brand-new queryable field: model_3d_urls
. This field will return an array of strings, each representing the URL of a 3D model associated with the product.
You can use a GraphQL client such as Altair GraphQL Client to make GraphQL queries easily. This can be useful when exploring an existing API as we did above, or to debug your own API, as we are about to do.
Make sure you set the API URL to http://localhost/graphql (assuming your M2 server is running at localhost
) and you're good to go β you can try out the example query from above!
Extending the GraphQL Schema
A GraphQL Schema is a document that describes the fields available in a GraphQL API. For example, there is a schema that specifies that the items
field of the products
query is an array of ProductInterface
. There is another schema file that describes the fields that are part of ProductInterface
:
Each field consists of a name for the field (like "id"), and a corresponding type (Int/String, etc.). This describes the values that the API is expected to have.
Because of the way GraphQL is setup in Magento, all of the schema files are merged together. This means that we can easily "extend" the ProductInterface
type to include other fields as well. All we need to do is create a new GraphQL schema file in our module (in etc/schema.graphqls
), and declare the additional ProductInterface
fields there:
And we have updated the GraphQL schema! Run magento setup:upgrade
for Magento to update it.
The exclamation mark (!
) means that the field cannot be null. This means that values such as model_3d_urls: null
and model_3d_urls: [null, null]
are not valid. It is a good idea to tell GraphQL that we expect these values to be present on any product if that is the case, because this will result in an error if the field is not set, helping catch bugs early.
Implementing the Field
Now, our ProductInterface
type provides an additional field. We have made a "promise" to API users that they can query a model_3d_urls
field on any product. Indeed, if we refresh the schema in our GraphQL client, we are now able to make a query such as this one:
However, if we send the query, we will get an error β because there is nothing in the current resolver that would populate model_3d_urls
with a value, and GraphQL is complaining that the data returned by the resolver does not match the schema we defined.
A GraphQL Resolver is an implementation of the schema. It is the PHP code that actually handles PHP requests and returns a data object of the response.
The products
query already has a resolver β that's the bit of code that returns the items
so that we can see the id
, name
and other fields. Now, we want to "plug in" to the resolver so that it returns the additional data we want.
The best way to "plug in" depends on how the resolver is implemented. Sometimes, we have to use Magento plugins (interceptors) to "wrap around" the resolver and add additional data before it returns. In this case, however, there is a specific class whose purpose is to process the product data after it is generated, but before it is returned through GraphQL.
The product DataPostProcessor
accepts an array of objects that implement the ProductsDataPostProcessorInterface
. Then, whenever the product collection is processed, it passes the data through each of the processor objects, allowing them to modify the data.
We can use the dependency injection configuration file to inject an additional processor:
Then, we can define that class and implement the functionality we want:
You can now verify that we can query the 3D Model URLs of the products and they will be returned correctly. Example response:
This works as expected β products with no 3D models get an empty array in model_3d_urls
and products with 3D models have an array of valid model URLs.
Last updated