@bradsearch/search-sdk
Version:
TypeScript SDK for BradSearch API with JWT authentication, field mapping, and faceted search capabilities
544 lines (425 loc) โข 11.1 kB
Markdown
# /search-sdk
A TypeScript SDK for BradSearch API with JWT authentication, field mapping, and faceted search capabilities.
## ๐ Installation
```bash
npm install /search-sdk
```
## ๐ Quick Start
```typescript
import { ApiClient } from "@bradsearch/search-sdk";
// Initialize the client
const client = new ApiClient({
token: "your-jwt-token",
baseUrl: "http://localhost:8080",
fields: {
name: { type: "text_keyword", filterable: false },
brand: { type: "text_keyword", filterable: true },
categories: { type: "hierarchy", filterable: true },
price: { type: "integer", filterable: true },
variants: {
type: "variants",
filterable: true,
fields: {
color: { type: "text_keyword", filterable: true },
size: { type: "keyword", filterable: true },
material: { type: "text_keyword", filterable: true },
},
},
},
mapping: {
title: "name",
reference: "sku",
link: "productUrl",
imageUrl: "imageUrl",
},
});
// Perform a search
const results = await client.query("laptop", {
brand: ["Dell", "HP"],
categories: ["Electronics > Computers"],
});
console.log(results.documents);
console.log(results.facets);
```
## ๐ง Configuration
### ApiClient Constructor
```typescript
interface ApiSdkConfig {
token: string; // JWT authentication token
baseUrl: string; // API base URL (e.g., 'http://localhost:8080')
fields: Record<string, FieldConfig>; // Field configurations
mapping?: ItemMapping; // Response field mapping (optional)
}
```
### Field Configuration
```typescript
interface FieldConfig {
type: FieldType; // Field type
filterable?: boolean; // Whether field can be used as filter (default: false)
fields?: Record<string, FieldConfig>; // For variants type - subfield configurations
label?: string; // Human-readable label for the field (optional)
}
type FieldType =
| "text" // Full-text search
| "keyword" // Exact match
| "text_keyword" // Both full-text and exact match
| "hierarchy" // Hierarchical categories (e.g., "Electronics > Computers")
| "variants" // Product variants
| "object" // Complex objects
| "url" // URLs
| "image_url" // Image URLs
| "integer"; // Numeric values
```
### Response Mapping
Map API response fields to the standard Item interface:
```typescript
interface ItemMapping {
title?: string; // Maps to item title
reference?: string; // Maps to item reference/SKU
link?: string; // Maps to item URL
imageUrl?: string; // Maps to item image URL
}
// Standard Item interface
interface Item {
id: string;
title: string;
link: string;
imageUrl: { small: string; medium: string };
reference: string;
_highlights?: Record<string, string>;
}
```
## ๐ Search Methods
### Basic Search
```typescript
// Simple text search
const results = await client.query("laptop");
// Search with options
const results = await client.query(
"laptop",
{},
{
limit: 20,
offset: 0,
sortBy: "name",
order: "asc",
}
);
```
### Search with Filters
```typescript
// Single filter
const results = await client.query("laptop", {
brand: "Dell",
});
// Multiple filters
const results = await client.query("laptop", {
brand: ["Dell", "HP"],
categories: ["Electronics > Computers > Laptops"],
price: ["100-500"], // Range filter
});
// Variant filters (using subfield names directly)
const results = await client.query("shirt", {
color: ["blue", "red"], // Variant attribute filter
size: ["M", "L"], // Another variant attribute filter
brand: ["Nike"], // Regular field filter
});
```
### Search All (Browse Mode)
```typescript
// Get all items without search query
const results = await client.query(
"",
{},
{
searchAll: true,
limit: 50,
}
);
```
### Request Cancellation
```typescript
const controller = new AbortController();
const results = await client.query(
"laptop",
{},
{
signal: controller.signal,
}
);
// Cancel the request
controller.abort();
```
## ๐ Response Format
```typescript
interface SearchResponse<T = Item> {
limit: number; // Items per page
total: number; // Total items found
offset: number; // Current offset
facets: Record<string, FacetValue[]>; // Available filters
documents: T[]; // Search results
}
interface FacetValue {
value: string; // Filter value
count: number; // Number of items with this value
}
```
## ๐ ๏ธ Advanced Usage
### Product Variants
Configure variant filtering for products with multiple options (color, size, etc.):
```typescript
// Configuration
const client = new ApiClient({
// ... other config
fields: {
// ... other fields
variants: {
type: "variants",
filterable: true,
fields: {
color: { type: "text_keyword", filterable: true },
size: { type: "keyword", filterable: true },
material: { type: "text_keyword", filterable: true },
},
},
},
});
// Filter by variant attributes (use subfield names directly)
const results = await client.query("", {
color: ["blue", "red", "green"],
size: ["S", "M", "L"],
});
```
### Custom Item Types
```typescript
interface CustomProduct {
id: string;
productName: string;
brandName: string;
categoryPath: string;
price: number;
}
const results = await client.query<CustomProduct>("laptop");
// results.documents will be CustomProduct[]
```
### Error Handling
```typescript
import {
ApiError,
AuthenticationError,
ValidationError,
NetworkError,
} from "@bradsearch/search-sdk";
try {
const results = await client.query("laptop");
} catch (error) {
if (error instanceof AuthenticationError) {
console.error("Invalid or expired JWT token");
} else if (error instanceof ValidationError) {
console.error("Invalid request parameters");
} else if (error instanceof NetworkError) {
console.error("Network connection failed");
} else if (error instanceof ApiError) {
console.error("API error:", error.statusCode, error.message);
}
}
```
### Utility Methods
```typescript
// Get filterable fields
const filterableFields = client.getFilterableFields();
// Update configuration
client.updateConfig({
fields: {
...client.config.fields,
newField: { type: "keyword", filterable: true },
},
});
```
## ๐ Hierarchy Filters
For hierarchical fields (categories), use " > " separator:
```typescript
const client = new ApiClient({
// ... other config
fields: {
categories: { type: "hierarchy", filterable: true },
},
});
// Filter by category hierarchy
const results = await client.query("", {
categories: [
"Electronics", // Top level
"Electronics > Computers", // Second level
"Electronics > Computers > Laptops", // Third level
],
});
```
## ๐งช Development
### Prerequisites
- Node.js >= 16.0.0
- npm or yarn
### Setup
```bash
# Clone the repository
git clone <repository-url>
cd SDK/typescript
# Install dependencies
npm install
# Build the package
npm run build
# Run tests
npm run test
# Run linting
npm run lint
```
### Development Scripts
```bash
npm run dev # Watch mode for development
npm run build # Build for production
npm run test # Run tests
npm run lint # Run ESLint
npm run storybook # Start Storybook demo
```
### Storybook Demo
Interactive demo with real API connections:
```bash
npm run storybook
```
Open http://localhost:6006 to see:
- Complete search interface
- Hierarchy filters with tree structure
- Configuration testing
- Field mapping examples
## ๐ฆ Publishing
### Preparing for Publication
1. **Update version**:
```bash
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
```
2. **Build and test**:
```bash
npm run build
npm run test
npm run lint
```
3. **Preview package contents**:
```bash
npm pack --dry-run
```
### Authentication
#### Login to npm
```bash
# Login with your npm account
npm login
# Verify authentication
npm whoami
```
#### Switch npm User
```bash
# Logout current user
npm logout
# Login with different account
npm login --registry https://registry.npmjs.org/
```
### Publishing to npm
#### First Time Publication
```bash
# Publish as public package (required for scoped packages)
npm publish --access public
```
#### Subsequent Releases
```bash
# Regular publish (after version bump)
npm publish
```
#### Publishing Beta/Alpha Versions
```bash
# Tag as beta
npm version prerelease --preid=beta
npm publish --tag beta
# Tag as alpha
npm version prerelease --preid=alpha
npm publish --tag alpha
```
### Automated Publishing
The package includes a `prepublishOnly` script that automatically builds before publishing:
```json
{
"scripts": {
"prepublishOnly": "npm run build"
}
}
```
### Package Configuration
Key `package.json` fields for publishing:
```json
{
"name": "@bradsearch/search-sdk",
"version": "1.0.0",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"dist/**/*.js.map",
"!dist/stories/**",
"!dist/setupTests.*",
"README.md"
],
"engines": {
"node": ">=16.0.0"
}
}
```
## ๐ Security
- **JWT Tokens**: Store securely, never commit to version control
- **HTTPS**: Always use HTTPS in production
- **CORS**: Configure your API server for cross-origin requests:
```javascript
// Example CORS headers for your API
Access-Control-Allow-Origin: https://your-domain.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
```
## ๐ Troubleshooting
### CORS Errors
If you get CORS errors, ensure your API server handles preflight OPTIONS requests:
```bash
# Test preflight request
curl -X OPTIONS http://localhost:8080/api/v1/query \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Authorization"
```
### Authentication Errors
- Verify JWT token is valid and not expired
- Ensure token contains necessary field configurations
- Check API endpoint accessibility
### Build Errors
```bash
# Clear dist folder and rebuild
rm -rf dist
npm run build
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install
```
## ๐ค Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/amazing-feature`
3. Commit changes: `git commit -m 'Add amazing feature'`
4. Push to branch: `git push origin feature/amazing-feature`
5. Open a Pull Request
## ๐ License
MIT License - see [LICENSE](LICENSE) file for details.
## ๐ Links
- [npm Package](https://www.npmjs.com/package/@bradsearch/search-sdk)
- [GitHub Repository](https://github.com/yourusername/bradsearch)
- [Documentation](https://github.com/yourusername/bradsearch#readme)
- [Issues](https://github.com/yourusername/bradsearch/issues)
## ๐ Support
For questions and support:
- Create an [issue](https://github.com/yourusername/bradsearch/issues)
- Email: contact@bradsearch.com