18 August 2021
Composable Commerce
HTTP API
Enhancement
GraphQLSearchProduct catalog

ProductProjection Search can now be performed using the GraphQL API.

Changes:

  • [GraphQL API] Added the following types to the GraphQL schema: CategoryOrderHintProductSearch, DimensionsProductSearch, DiscountedProductSearchPriceValue, ExistsFilterInput, FacetResult, FacetResultValue, ImageProductSearch, MissingFacetInput, MissingFilterInput, PriceSelectorInput, ProductPriceSearch, ProductProjection, ProductProjectionSearchResult, ProductSearchPriceTier, ProductSearchVariant, ProductSearchVariantAvailabilitiesResult, ProductSearchVariantAvailability, ProductSearchVariantAvailabilityWithChannel, ProductSearchVariantAvailabilityWithChannels, RangeCount, RangeCountDouble, RangeCountLong, RangeElementInput, RangeFacetInput, RangeFacetResult, RangeFilterInput, RawProductSearchAttribute, SearchFacetInput, SearchFacetModelInput, SearchFilterInput, SearchFilterModelInput, SearchKeywordProductSearch, SearchKeywordsProductSearch, SuggestTokenizerProductSearch,CustomSuggestTokenizerProductSearch,WhitespaceSuggestTokenizerProductSearch, TermCount, TermsFacetInput, TermsFacetResult, TreeFacetInput, TreeFilterInput, ValueCountFacetInput, ValueFacetInput, ValueFacetResult, ValueFilterInput.
  • [GraphQL API] Changed the Query type:
    • Added the productProjectionSearch field to the Query type.

The following changes were introduced in terms of GraphQL SDL:

extend type Query {
  productProjectionSearch(locale: Locale, text: String, facets: [SearchFacetInput!]! = [], filters: [SearchFilterInput!]! = [], queryFilters: [SearchFilterInput!]! = [], facetFilters: [SearchFilterInput!]! = [], sorts: [String!]! = [], limit: Int! = 10, offset: Int! = 0, fuzzy: Boolean! = false, fuzzyLevel: Int, priceSelector: PriceSelectorInput, markMatchingVariant: Boolean! = false,

    "BETA: This feature can be subject to change and should be used carefully in production. https://docs.commercetools.com/api/contract#public-beta"
    storeProjection: String,

    "BETA: This feature can be subject to change and should be used carefully in production. https://docs.commercetools.com/api/contract#public-beta"
    localeProjection: [Locale!], staged: Boolean = false): ProductProjectionSearchResult!
}

type CategoryOrderHintProductSearch {
  categoryId: String!
  orderHint: String!
}

type DimensionsProductSearch {
  width: Int!
  height: Int!
}

type DiscountedProductSearchPriceValue {
  value: BaseMoney!
  discountRef: Reference!
  discount: ProductDiscount
}

input ExistsFilterInput {
  path: String!
}

interface FacetResult {
  type: String!
}

type FacetResultValue {
  facet: String!
  value: FacetResult!
}

type ImageProductSearch {
  url: String!
  dimensions: DimensionsProductSearch!
  label: String
}

input MissingFacetInput {
  path: String!
  alias: String
}

input MissingFilterInput {
  path: String!
}

input PriceSelectorInput {
  currency: Currency!
  country: Country
  customerGroup: ReferenceInput
  channel: ReferenceInput
  date: Instant!
}

scalar Instant

type ProductPriceSearch {
  id: String
  value: BaseMoney!
  country: Country
  customerGroup: CustomerGroup
  customerGroupRef: Reference
  channel: Channel
  channelRef: Reference
  validFrom: DateTime
  validUntil: DateTime
  discounted: DiscountedProductSearchPriceValue
  tiers: [ProductSearchPriceTier!]
  custom: CustomFieldsType
}

type ProductProjection {
  id: String!
  version: Long!
  createdAt: DateTime!
  lastModifiedAt: DateTime!
  productTypeRef: Reference!
  productType: ProductTypeDefinition
  name(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  nameAllLocales: [LocalizedString!]!
  description(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  descriptionAllLocales: [LocalizedString!]
  slug(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  slugAllLocales: [LocalizedString!]!
  categoryOrderHints: [CategoryOrderHintProductSearch!]!
  categoriesRef: [Reference!]!
  categories: [Category!]!
  searchKeywords: [SearchKeywordsProductSearch!]!
  metaTitle(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  metaTitleAllLocales: [LocalizedString!]
  metaKeywords(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  metaKeywordsAllLocales: [LocalizedString!]
  metaDescription(
    "String is defined for different locales. This argument specifies the desired locale."
    locale: Locale,

    "List of languages the client is able to understand, and which locale variant is preferred."
    acceptLanguage: [Locale!]): String
  metaDescriptionAllLocales: [LocalizedString!]
  hasStagedChanges: Boolean!
  published: Boolean!
  masterVariant: ProductSearchVariant!
  variants: [ProductSearchVariant!]!
  taxCategoryRef: Reference
  taxCategory: TaxCategory
  stateRef: Reference
  state: State
  reviewRatingStatistics: ReviewRatingStatistics
}

type ProductProjectionSearchResult {
  offset: Int!
  count: Int!
  total: Int!
  results: [ProductProjection!]!
  facets: [FacetResultValue!]!
}

type ProductSearchPriceTier {
  minimumQuantity: Int!
  value: BaseMoney!
}

type ProductSearchVariant {
  id: Int!
  key: String
  sku: String
  prices: [ProductPriceSearch!]

  "Returns a single price based on the price selection rules."
  price(currency: Currency!, country: Country, customerGroupId: String, channelId: String, date: DateTime): ProductPriceSearch
  images: [ImageProductSearch!]!
  assets: [Asset!]!
  availability: ProductSearchVariantAvailabilityWithChannels

  "This field contains raw attributes data"
  attributesRaw(
    """
    The names of the attributes to include.

    If neither `includeNames` nor `excludeNames` are provided, then all attributes are returned.
    """
    includeNames: [String!],

    """
    The names of the attributes to exclude.

    If neither `includeNames` nor `excludeNames` are provided, then all attributes are returned.
    """
    excludeNames: [String!]): [RawProductSearchAttribute!]!
}

"Product variant availabilities"
type ProductSearchVariantAvailabilitiesResult {
  limit: Int
  offset: Int
  total: Int!
  results: [ProductSearchVariantAvailabilityWithChannel!]!
}

"Product variant availability"
type ProductSearchVariantAvailability {
  isOnStock: Boolean!
  restockableInDays: Int
  availableQuantity: Long
}

type ProductSearchVariantAvailabilityWithChannel {
  channelRef: Reference!
  channel: Channel
  availability: ProductSearchVariantAvailability!
}

type ProductSearchVariantAvailabilityWithChannels {
  noChannel: ProductSearchVariantAvailability
  channels(
    """
    The IDs of channels to include.

    If neither `includeChannelIds` nor `excludeChannelIds` are provided, then all channels are returned.
    """
    includeChannelIds: [String!],

    """
    The IDs of channels to exclude.

    If neither `includeChannelIds` nor `excludeChannelIds` are provided, then all channels are returned.
    """
    excludeChannelIds: [String!], limit: Int, offset: Int): ProductSearchVariantAvailabilitiesResult!
}

interface RangeCount {
  type: String!
}

type RangeCountDouble implements RangeCount {
  from: Float!
  fromStr: String!
  to: Float!
  toStr: String!
  count: Int!
  productCount: Int
  totalCount: Int!
  total: Float!
  min: Float!
  max: Float!
  mean: Float!
  type: String!
}

type RangeCountLong implements RangeCount {
  from: Long!
  fromStr: String!
  to: Long!
  toStr: String!
  count: Int!
  productCount: Int
  totalCount: Int!
  total: Long!
  min: Long!
  max: Long!
  mean: Float!
  type: String!
}

input RangeElementInput {
  from: String!
  to: String!
}

input RangeFacetInput {
  path: String!
  ranges: [RangeElementInput!]!
  alias: String
  countProducts: Boolean! = false
}

type RangeFacetResult implements FacetResult {
  dataType: String!
  ranges: [RangeCount!]!
  type: String!
}

input RangeFilterInput {
  path: String!
  ranges: [RangeElementInput!]!
}

type RawProductSearchAttribute {
  name: String!
  value: Json!
}

input SearchFacetInput {
  "BETA: This feature can be subject to change and should be used carefully in production. https://docs.commercetools.com/api/contract#public-beta"
  model: SearchFacetModelInput
  string: String
}

input SearchFacetModelInput {
  terms: TermsFacetInput
  value: ValueFacetInput
  range: RangeFacetInput
  tree: TreeFacetInput
  valueCount: ValueCountFacetInput
  missing: MissingFacetInput
}

input SearchFilterInput {
  "BETA: This feature can be subject to change and should be used carefully in production. https://docs.commercetools.com/api/contract#public-beta"
  model: SearchFilterModelInput
  string: String
}

input SearchFilterModelInput {
  value: ValueFilterInput
  range: RangeFilterInput
  missing: MissingFilterInput
  exists: ExistsFilterInput
  tree: TreeFilterInput
}

type SearchKeywordProductSearch {
  text: String!
  suggestTokenizer: SuggestTokenizerProductSearch
}

type SearchKeywordsProductSearch {
  locale: Locale!
  searchKeywords: [SearchKeywordProductSearch!]!
}

interface SuggestTokenizerProductSearch {
  type: String!
}

type CustomSuggestTokenizerProductSearch implements SuggestTokenizerProductSearch {
  inputs: [String!]!
  type: String!
}

type WhitespaceSuggestTokenizerProductSearch implements SuggestTokenizerProductSearch {
  type: String!
}

type TermCount {
  term: String!
  count: Int!
  productCount: Int
}

input TermsFacetInput {
  path: String!
  alias: String
  countProducts: Boolean! = false
}

type TermsFacetResult implements FacetResult {
  dataType: String!
  missing: Int!
  total: Int!
  other: Int!
  terms: [TermCount!]!
  type: String!
}

input TreeFacetInput {
  path: String!
  rootValues: [String!]!
  subTreeValues: [String!]!
  alias: String
  countProducts: Boolean! = false
}

input TreeFilterInput {
  path: String!
  rootValues: [String!]!
  subTreeValues: [String!]!
}

input ValueCountFacetInput {
  path: String!
  alias: String
}

input ValueFacetInput {
  path: String!
  values: [String!]!
  alias: String
  countProducts: Boolean! = false
}

type ValueFacetResult implements FacetResult {
  count: Int!
  productCount: Int
  type: String!
}

input ValueFilterInput {
  path: String!
  values: [String!]!
}