// backend/products.jsw
import {ok, notFound, serverError} from 'wix-http-functions';
import wixData from 'wix-data';
export async function get_products(request) {
try {
const options = {
suppressAuth: true // Careful with this! Implement proper authentication
};
let query = wixData.query("Products"); // Assuming your collection is named "Products"
// Add filtering, sorting, and pagination based on request.query parameters
const results = await query.find(options);
const response = {
headers: {
"Content-Type": "application/json",
},
body: {
products: results.items,
totalCount: results.totalCount, // For pagination
// ... other relevant data
},
};
return ok(response);
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// Similar functions for POST, PUT, DELETE
// Page Code (Example - Product Display)
import {fetch} from 'wix-fetch';
$w.onReady(async function () {
// Fetch products from the API
const response = await fetch("/_functions/products", {method: 'get'}); // Use the correct endpoint URL
if (response.ok) {
const data = await response.json();
// Populate a repeater with the product data
$w("#productRepeater").data = data.products;
$w("#productRepeater").onItemReady(($item, itemData, index) => {
// Set the repeater item elements based on the product data
$item("#productName").text = itemData.name;
$item("#productDescription").text = itemData.description;
$item("#productImage").src = itemData.imageURL; // Assuming you have an Image element
$item("#productPrice").text = `$${itemData.price.toFixed(2)}`;
$item("#addToCartButton").onClick(() => {
// Handle adding the product to the cart (implementation depends on your cart logic)
console.log(`Adding ${itemData.name} to cart`);
// You might use Wix Stores for cart functionality, or implement your own
});
// ... set other elements (THC, CBD, etc.) ...
});
} else {
console.error("Error fetching products:", response.status);
// Handle the error (e.g., display an error message to the user)
}
// Set up event handlers for filtering and sorting
$w("#typeFilter").onChange(() => filterProducts()); // Dropdown for product type
$w("#strainSearch").onInput(() => filterProducts()); // Input for strain search
$w("#sortSelect").onChange(() => filterProducts());
//Implement filter and sorting of products
async function filterProducts() {
const type = $w("#typeFilter").value;
const strain = $w("#strainSearch").value;
const sortBy = $w("#sortSelect").value;
let url = "/_functions/products?";
if (type) url += `type=${type}&`;
if (strain) url += `strain=${strain}&`;
if (sortBy) url += `sort=${sortBy}&`;
//Remove the last char from string if '&'
url = url.slice(0, -1);
const response = await fetch(url, { method: 'get' });
//Re-populate the repeater with the response
if (response.ok) {
const data = await response.json();
// Populate a repeater with the product data
$w("#productRepeater").data = data.products;
$w("#productRepeater").onItemReady(($item, itemData, index) => {
// Set the repeater item elements based on the product data
$item("#productName").text = itemData.name;
$item("#productDescription").text = itemData.description;
$item("#productImage").src = itemData.imageURL; // Assuming you have an Image element
$item("#productPrice").text = `$${itemData.price.toFixed(2)}`;
$item("#addToCartButton").onClick(() => {
// Handle adding the product to the cart (implementation depends on your cart logic)
console.log(`Adding ${itemData.name} to cart`);
// You might use Wix Stores for cart functionality, or implement your own
});
// ... set other elements (THC, CBD, etc.) ...
});
} else {
console.error("Error fetching products:", response.status);
// Handle the error (e.g., display an error message to the user)
}
}
});
// backend/cannabisAPI.jsw
import {ok, notFound, badRequest, serverError, forbidden} from 'wix-http-functions';
import wixData from 'wix-data';
import {fetch} from 'wix-fetch';
// --- Helper Functions ---
// VERY BASIC scraping example. DO NOT RELY ON THIS FOR PRODUCTION.
async function scrapeProductData(url) {
try {
const response = await fetch(url, {method: 'get'});
if (!response.ok) {
console.error(`Scraping failed for ${url}: ${response.status}`);
return null;
}
const html = await response.text();
// *** Extremely simplified parsing - You'll need MUCH more robust logic ***
// This is just to illustrate the *concept*. Use a library like Cheerio
// on a separate server for real-world scraping.
const productName = html.match(/(.*?)<\/h1>/)?.[1]; // Extremely fragile!
const productDescription = html.match(/(.*?)<\/p>/)?.[1]; // Extremely fragile!
if (!productName) return null
return {
name: productName,
description: productDescription,
// ... extract other data (THC, CBD, image URL, etc.) ...
};
} catch (error) {
console.error(`Error scraping ${url}:`, error);
return null;
}
}
// --- API Endpoints ---
// Get all products (with filtering and pagination)
export async function get_products(request) {
try {
// --- AGE VERIFICATION (ESSENTIAL - Integrate with a service!) ---
// You MUST verify the user's age before allowing access to product data.
// This is a placeholder. Replace with a real age verification check.
// const ageVerified = await verifyUserAge(request); // Hypothetical function
// if (!ageVerified) {
// return forbidden({body: {error: 'Age verification failed'}});
// }
const options = {
suppressAuth: true // Only if age verification is handled elsewhere!
};
let query = wixData.query("Products");
// Filtering (example - add more based on your needs)
if (request.query.type) {
query = query.eq("Type", request.query.type); // e.g., ?type=flower
}
if (request.query.strain) {
query = query.contains("Strain", request.query.strain); // e.g., ?strain=kush
}
if (request.query.brand) {
query = query.contains("Brand", request.query.brand);
}
// Pagination
const limit = parseInt(request.query.limit) || 20;
const skip = parseInt(request.query.offset) || 0;
query = query.limit(limit).skip(skip);
const results = await query.find(options);
return ok({
headers: {"Content-Type": "application/json"},
body: {
products: results.items,
totalCount: results.totalCount,
},
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// Get a single product by ID
export async function get_products_id(request) {
try {
const options = {
suppressAuth: true // Only if age verification is handled elsewhere!
};
const productId = request.path[0];
const product = await wixData.get("Products", productId, options);
if (!product) {
return notFound({body: {error: 'Product not found'}});
}
return ok({
headers: {"Content-Type": "application/json"},
body: product,
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// Add a product (ADMIN ONLY - Requires authentication)
export async function post_products(request) {
try {
// --- Authentication (ESSENTIAL) ---
// You MUST authenticate the user (e.g., using Wix Members Area)
// and check if they have admin privileges before allowing product creation.
// This is a placeholder. Implement proper authentication!
// if (!isAdminUser(request)) {
// return forbidden({body: {error: 'Unauthorized'}});
// }
const options = {
suppressAuth: true
};
const productData = await request.body.json();
// --- Data Validation (ESSENTIAL) ---
// Validate ALL fields (name, description, THC, CBD, etc.)
// to ensure data integrity and prevent errors.
if (!productData.name || !productData.description || !productData.price) {
return badRequest({body: {error: 'Missing required fields'}});
}
// --- Scrape Data (Optional - Use with caution) ---
// If a scraping URL is provided, attempt to scrape additional data.
// if (productData.scrapeUrl) {
// const scrapedData = await scrapeProductData(productData.scrapeUrl);
// if (scrapedData) {
// // Merge scraped data with provided data (prioritize provided data)
// productData = {...scrapedData, ...productData};
// }
// }
const toSave = {
"title": productData.name, // Use "title" for Wix Data primary field
...productData, // Spread the rest of the product data
};
const result = await wixData.insert("Products", toSave, options);
return ok({
headers: {"Content-Type": "application/json"},
body: result,
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// --- Other Endpoints (Orders, Customers, Reviews) ---
// Implement similar endpoints for creating, retrieving, updating,
// and deleting orders, customers, and reviews. Include robust
// authentication and authorization as needed. Remember age verification
// for all customer-related actions.
//Example function to get orders.
export async function get_orders(request) {
try {
const options = {
suppressAuth: true //Requires secure authentication to implement
};
let query = wixData.query("Orders");
const results = await query.find(options);
return ok({
headers: {"Content-Type": "application/json"},
body: {
products: results.items,
totalCount: results.totalCount,
},
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// --- Scheduled Task (Example - for scraping) ---
// You can use Wix's Scheduled Jobs to run scraping tasks periodically.
// This is a VERY basic example. You'll need a much more sophisticated
// solution for real-world scraping, possibly involving a separate server.
// export async function scheduledScrape() {
// const sitesToScrape = ['https://example.com/products', 'https://another-site.com/menu'];
// for (const url of sitesToScrape) {
// const scrapedData = await scrapeProductData(url);
// if (scrapedData) {
// // Process and save the scraped data to your "Products" collection.
// // Handle potential duplicates, updates, etc.
// }
// }
// }
top of page
Search
All Posts
Check back soon
Once posts are published, you’ll see them here.
bottom of page
// backend/cannabisAPI.jsw
import {ok, notFound, badRequest, serverError, forbidden} from 'wix-http-functions';
import wixData from 'wix-data';
import {fetch} from 'wix-fetch';
// --- Helper Functions ---
// VERY BASIC scraping example. DO NOT RELY ON THIS FOR PRODUCTION.
async function scrapeProductData(url) {
try {
const response = await fetch(url, {method: 'get'});
if (!response.ok) {
console.error(`Scraping failed for ${url}: ${response.status}`);
return null;
}
const html = await response.text();
// *** Extremely simplified parsing - You'll need MUCH more robust logic ***
// This is just to illustrate the *concept*. Use a library like Cheerio
// on a separate server for real-world scraping.
const productName = html.match(/(.*?)<\/h1>/)?.[1]; // Extremely fragile!
const productDescription = html.match(/(.*?)<\/p>/)?.[1]; // Extremely fragile!
if (!productName) return null
return {
name: productName,
description: productDescription,
// ... extract other data (THC, CBD, image URL, etc.) ...
};
} catch (error) {
console.error(`Error scraping ${url}:`, error);
return null;
}
}
// --- API Endpoints ---
// Get all products (with filtering and pagination)
export async function get_products(request) {
try {
// --- AGE VERIFICATION (ESSENTIAL - Integrate with a service!) ---
// You MUST verify the user's age before allowing access to product data.
// This is a placeholder. Replace with a real age verification check.
// const ageVerified = await verifyUserAge(request); // Hypothetical function
// if (!ageVerified) {
// return forbidden({body: {error: 'Age verification failed'}});
// }
const options = {
suppressAuth: true // Only if age verification is handled elsewhere!
};
let query = wixData.query("Products");
// Filtering (example - add more based on your needs)
if (request.query.type) {
query = query.eq("Type", request.query.type); // e.g., ?type=flower
}
if (request.query.strain) {
query = query.contains("Strain", request.query.strain); // e.g., ?strain=kush
}
if (request.query.brand) {
query = query.contains("Brand", request.query.brand);
}
// Pagination
const limit = parseInt(request.query.limit) || 20;
const skip = parseInt(request.query.offset) || 0;
query = query.limit(limit).skip(skip);
const results = await query.find(options);
return ok({
headers: {"Content-Type": "application/json"},
body: {
products: results.items,
totalCount: results.totalCount,
},
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// Get a single product by ID
export async function get_products_id(request) {
try {
const options = {
suppressAuth: true // Only if age verification is handled elsewhere!
};
const productId = request.path[0];
const product = await wixData.get("Products", productId, options);
if (!product) {
return notFound({body: {error: 'Product not found'}});
}
return ok({
headers: {"Content-Type": "application/json"},
body: product,
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// Add a product (ADMIN ONLY - Requires authentication)
export async function post_products(request) {
try {
// --- Authentication (ESSENTIAL) ---
// You MUST authenticate the user (e.g., using Wix Members Area)
// and check if they have admin privileges before allowing product creation.
// This is a placeholder. Implement proper authentication!
// if (!isAdminUser(request)) {
// return forbidden({body: {error: 'Unauthorized'}});
// }
const options = {
suppressAuth: true
};
const productData = await request.body.json();
// --- Data Validation (ESSENTIAL) ---
// Validate ALL fields (name, description, THC, CBD, etc.)
// to ensure data integrity and prevent errors.
if (!productData.name || !productData.description || !productData.price) {
return badRequest({body: {error: 'Missing required fields'}});
}
// --- Scrape Data (Optional - Use with caution) ---
// If a scraping URL is provided, attempt to scrape additional data.
// if (productData.scrapeUrl) {
// const scrapedData = await scrapeProductData(productData.scrapeUrl);
// if (scrapedData) {
// // Merge scraped data with provided data (prioritize provided data)
// productData = {...scrapedData, ...productData};
// }
// }
const toSave = {
"title": productData.name, // Use "title" for Wix Data primary field
...productData, // Spread the rest of the product data
};
const result = await wixData.insert("Products", toSave, options);
return ok({
headers: {"Content-Type": "application/json"},
body: result,
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// --- Other Endpoints (Orders, Customers, Reviews) ---
// Implement similar endpoints for creating, retrieving, updating,
// and deleting orders, customers, and reviews. Include robust
// authentication and authorization as needed. Remember age verification
// for all customer-related actions.
//Example function to get orders.
export async function get_orders(request) {
try {
const options = {
suppressAuth: true //Requires secure authentication to implement
};
let query = wixData.query("Orders");
const results = await query.find(options);
return ok({
headers: {"Content-Type": "application/json"},
body: {
products: results.items,
totalCount: results.totalCount,
},
});
} catch (error) {
return serverError({body: {error: error.message}});
}
}
// --- Scheduled Task (Example - for scraping) ---
// You can use Wix's Scheduled Jobs to run scraping tasks periodically.
// This is a VERY basic example. You'll need a much more sophisticated
// solution for real-world scraping, possibly involving a separate server.
// export async function scheduledScrape() {
// const sitesToScrape = ['https://example.com/products', 'https://another-site.com/menu'];
// for (const url of sitesToScrape) {
// const scrapedData = await scrapeProductData(url);
// if (scrapedData) {
// // Process and save the scraped data to your "Products" collection.
// // Handle potential duplicates, updates, etc.
// }
// }
// }