Overview
The Tapcart searchClient
allows blocks to fetch product, recommendation, and filter data from different integrations. The searchClient
follows a strategy pattern with a base class (BaseSearchClient
) that provides common functionality and abstract methods that concrete implementations must provide. This architecture allows for extensive customization while maintaining consistency across different search providers. You can use and customize the searchClient
at the block level. You can share the searchClient
across all blocks on the layout, or create instances of the searchClient
for individual blocks.
The following doc outlines:
- Core Architecture & Types
- Common methods
- Access patterns
- Tapcart Patterns
- Customizations
Supported Integrations
Integration | Status | Availability |
---|---|---|
Algolia | supported | All Pages and Blocks |
Nosto | supported | All Pages and Blocks |
Search Spring | supported | All Pages and Blocks |
Fast Simon | supported | All Pages and Blocks |
Google Search | coming soon | None |
Searchanise | coming soon | None |
Core Architecture & Types
The searchClient
uses TypeScript interfaces and abstract classes to provide a consistent API across different search providers.
Core Interfaces
interface SearchParams {
query?: string
sort?: string
filters?: Record<string, Set<string>>
collection?: string
page?: number
productsPerPage?: number
}
interface SearchResponse<T = any> {
products: T[]
page: number
totalPages: number
totalProducts: number
facets?: Record<string, any>
nextPage?: number | null
hasMore: boolean
}
interface QueryParams {
collectionHandle?: string
collectionId?: string
sort_by?: string
filter?: string[]
searchQuery?: string
[key: string]: any
}
interface FormattedFilter {
title: string
image: string | null
tag: string
amount: number
isSelected: boolean
collectionId: string | null
min: number | null
max: number | null
}
interface FormattedFacet {
title: string
filters: FormattedFilter[]
field: string | null
multiSelect: boolean | null
id: string | null
}
interface SearchConfig {
"sort-options"?: Array<{
label: string
key: string
}>
"filter-options"?: Array<{
label: string
key: string
}>
enabled: boolean
name: string
[key: string]: any
}
Base Search Client Structure
// Base search client interface
export abstract class BaseSearchClient<T = any> {
// Public methods for state management
// Protected methods for customization
// Abstract methods that are implemented by the integration classes
}
Data Flow
graph TD A[Code.js Block] --> B[useSearchContext/useSearchInstance] B --> C[Search Client Instance] C --> D[useInfiniteScroll/useRecommendations] D --> E[searchClient.fetcher/getRecommendations] E --> F[Provider API] F --> G[Response Processing] G --> H[Product Data] H --> I[UI Rendering] C --> J[State Management] J --> K[Filters/Sort/Collection] K --> L[applyBaseParamsToIntegration] L --> E
Best Practices
- Always bind methods when overriding to preserve
this
context - Call original methods when extending functionality to maintain base behavior
- Handle errors gracefully in custom implementations
- Clean up event listeners to prevent memory leaks
- Cache expensive operations in custom implementations
- Validate input parameters in custom methods
Updated about 9 hours ago