Skip to content

Conversation

@leozhang14
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[x] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

Shopify category driver has not been implemented at all.

Fixes: N/A

What is the new behavior?

Shopify category driver has been implemented fully. Most of the functionality is complete with a few missing parts (potentially blocked by missing product/driver features - todo): specifically breadcrumbs, pagination, and some product filtering options (todo). These issues should not affect the the functionality of the category driver.

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

@leozhang14 leozhang14 self-assigned this Apr 1, 2025
@leozhang14 leozhang14 requested a review from a team as a code owner April 1, 2025 04:47
Copy link
Member

@griest024 griest024 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Just a couple of minor things to change.

Comment on lines 12 to 46
handle
id
title
description
onlineStoreUrl
image {
altText
id
url
}
products(first: 10, reverse: $reverse, sortKey: $sortKey, filters: $filters) {
nodes {
handle
onlineStoreUrl
availableForSale
priceRange {
maxVariantPrice {
amount
currencyCode
}
minVariantPrice {
amount
currencyCode
}
}
id
title
description
images(first: 1) {
nodes {
id
url
altText
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type should be broken down into a few fragments. I'd say you should make Collection, Image, Product, and Price fragments.

* @param sortkey - string
* @returns ShopifyProductCollectionSortKeys
*/
export const shopifyProductCollectionSortKeyValidator = (sortkey: string): ShopifyProductCollectionSortKeys => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel like a validator to me. IMO, a validator does not change the response, only ensures that it meets a spec, and if not, throws an error. I think this function is valuable, but its more of a coercion than a validator. Its definitely a minor issue but still important for maintaining proper separation of concerns. Its possible that there are other validators in the codebase that do change the response, and they're wrong to do so, IMO.

@damienwebdev As an aside, I feel like there's an opportunity to define what a validator is in the context of a driver. I think its a function that takes the response and returns void. Any influence it has should only be with throwing errors. i.e.:

export type DaffDriverGraphqlValidator<T> = (response: ApolloQueryResult<T>) => void

Comment on lines 14 to 15
* @param node - ShopifyImageNode
* @param type - string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its unnecessary to annotate params with the type in TS, the type will be pulled from the function signature. If you want to add descriptions, that's a good place. For example

/**
   * Transforms the magento CartPayment from the magento cart query into a DaffCartPaymentMethod.
   *
   * @param responsePayment - the response from a magento cart query.
   */
  transform(responsePayment: MagentoCartPaymentMethod): DaffCartPaymentMethod

is rendered in daff.io (eventually) as:
image

import { ShopifyImageNode } from '@daffodil/driver/shopify';

class MockShopifyImageNode implements ShopifyImageNode {
id = '';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faker should have a uuid generator that you can use here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string is meant to be empty. If you follow the logic, the id is supposed to be empty, and is filled out later based on what kind of ImageNode is meant to be created (e.g. ProductImage, CollectionImage, etc.). I don't think Shopify uses uuid anyways.

Here are some examples of a Shopify id:

gid://shopify/Product/7807187157028
gid://shopify/Collection/463004860452
gid://shopify/ProductImage/34216320925732

@leozhang14 leozhang14 force-pushed the shopify-category-driver branch from 09e1e15 to 1e1ba56 Compare April 22, 2025 23:02
@leozhang14
Copy link
Contributor Author

leozhang14 commented Apr 23, 2025

As the PR most likely won't be fully merged by the time my internship ends, I just wanted to leave a few notes. Some of these are not specific to category, but relevant to Shopify in general.

The shopify category driver is complete and implements all required functionality. However, there are a few considerations.

DaffFilterRequest Structure
The implementation of the category driver relies on the following assumptions, as it is unclear how exactly the DaffFIlterRequest fields map to ShopifyProductFilter fields.
name → identifier shown in UI / analytics logs.
value → array carrying the raw filter request:
value[0] = Shopify ProductFilter type (tag, price, variantMetafield, etc.).
value[1…] = payload specific to that filter (the category driver assumes that this contains all the information required for the shopify query)

Or vs And Filters in Shopify
Filters use OR if they are the same type (i.e. filtering on Canada, USA will return products that belong to either)
Filters use AND if they are different types (i.e. filtering on Canada, Metal will return products that are both Canadian and Metal material)
Filtering information is contained here (Shopify requries the use of an app called Search and Discovery)

Schema + codegen workflow

cd libs/driver/shopify/src/codegen

Download the latest Storefront schema:

apollo schema:download ./storefront-schema.json \
  --endpoint=https://{store_name}.myshopify.com/api/{latest}/graphql.json \
  --header "X-Shopify-Storefront-Access-Token: {ACCESS_TOKEN}"

Generate TS types & operations:
npm run shopify:codegen:generate

CodeClimate Errors
There are some CodeClimate errors specific to code complexity and the length of a function. I'm not particularly sure how these errors can/should be resolved.

PR Breakdown:
In my opinion, the code changes contained in this PR should be split into separate PRs.

Shopify driver – extra transforms, shared fragments, general reorganization of the driver (split into commits)

Shopify Category service – new queries, category-specific transforms, etc.

Product query – modify existing product query and category service spec to accommodate the fragment changes

@damienwebdev damienwebdev marked this pull request as draft December 30, 2025 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants