Last active
February 27, 2024 00:44
-
-
Save Lissy93/444a1dcf8bb6763a8ab9da8451544321 to your computer and use it in GitHub Desktop.
API for UK food product photos (via Cloudflare Workers)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Cloudflare Worker script for displaying UK food products | |
* Fetches given item from Tesco.com using search endpoint | |
* Optionally resizes to specified dimensions | |
* Implements caches recently requested images | |
* Swaers a little bit when an error happens | |
*/ | |
addEventListener('fetch', event => { | |
event.respondWith(handleRequest(event.request, event)) | |
}) | |
const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'; | |
const TESCO_SEARCH_URL = 'https://www.tesco.com/groceries/en-GB/search?query='; | |
const WELCOME = 'Welcome to the Snack Champion\'s product photo API! 🥤🍬🍿😋\n' + | |
'To use this service, please specify a product name and optional dimensions.'; | |
async function handleRequest(request, event) { | |
const cacheUrl = new URL(request.url); | |
const cacheKey = new Request(cacheUrl.toString(), request); | |
const cache = caches.default; | |
// Check if the response is already in the cache | |
let response = await cache.match(cacheKey); | |
if (response) { | |
return response; // Return the cached response if it exists | |
} | |
try { | |
const { productName, dimension } = extractProductAndDimension(request.url); | |
if (!productName) { | |
return new Response(WELCOME, { status: 418 }); | |
} | |
const imageURL = await fetchProductImageURL(productName, dimension); | |
if (imageURL) { | |
response = await fetchAndReturnImage(imageURL); | |
// Store the fetched response in the cache. | |
event.waitUntil(cache.put(cacheKey, response.clone())); | |
return response; | |
} else { | |
return new Response("Image not found. Fuck sake", { status: 404 }); | |
} | |
} catch (error) { | |
console.error(error); // Log the error for debugging | |
return new Response("An error occurred. Shit", { status: 500 }); | |
} | |
} | |
function extractProductAndDimension(url) { | |
const pathSegments = new URL(url).pathname.split("/").filter(Boolean); | |
return { | |
productName: pathSegments[0], | |
dimension: pathSegments[1] // undefined if not present | |
}; | |
} | |
async function fetchProductImageURL(product, dimension) { | |
const response = await fetch(`${TESCO_SEARCH_URL}${product}`, { headers: { 'User-Agent': USER_AGENT } }); | |
const body = await response.text(); | |
const match = body.match(/(https:\/\/digitalcontent\.api\.tesco\.com\/v2\/media\/[^?]+)/); | |
if (match) { | |
let imageURL = match[0]; | |
if (dimension) { | |
imageURL += `?h=${dimension}&w=${dimension}`; | |
} | |
return imageURL; | |
} else { | |
return null; | |
} | |
} | |
async function fetchAndReturnImage(imageURL) { | |
const response = await fetch(imageURL); | |
const imageBlob = await response.blob(); | |
return new Response(imageBlob, { | |
headers: { 'Content-Type': response.headers.get('Content-Type') } | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Docs
About
A simple script for embedding product images into a website.
E.g.
<img src="https://snack-product-photo.as93.workers.dev/biscuits/128" />
Data is scraped from Tesco, and the service can be easily deployed as a serverless function.
Deployment
Log in to Cloudflare, navigate to "Workers" and then "New" / "Quick Edit".
Paste the above script in, and then hit "Save & Deploy". Done :)
Usage
/
- Homepage (Example:/
)/[item-name]
- Image of a given item (Example:/cheese
)/[item-name]/[image-width]
- Image of a given item, using spacified dimensions (Example:/bread/128
)Demo
A live demo is hosted at: snack-product-photo.as93.workers.dev
License
Licensed under MIT, © Alicia Sykes 2023