Skip to content

Instantly share code, notes, and snippets.

@freshyjmp
Last active July 8, 2021 07:04
Show Gist options
  • Save freshyjmp/d2589f90bdee7a883e5d2441cab9b982 to your computer and use it in GitHub Desktop.
Save freshyjmp/d2589f90bdee7a883e5d2441cab9b982 to your computer and use it in GitHub Desktop.
rudimentary example of using custom functions to make API requests w/caching service in Google App Script
var public_key = 'SET THIS YOURSELF';
var private_key = 'ALSO SET THIS YOURSELF';
var cache = CacheService.getDocumentCache();
const CACHE_KEY = 'cardboard_wealth_token_response';
const GROUP_KEY = 'mtg_groups';
const PRICE_KEY = 'mtg_prices';
const PRODUCT_KEY = 'mtd_products';
function refreshToken() {
// We're lazy and like to keep our token response in our super secure app script
// If the bearer token has expired, request a new one. Otherwise, nah.
var formData = {
'grant_type': 'client_credentials',
'client_id': public_key,
'client_secret': private_key
};
var options = {
'headers': {
'User-Agent': "update this yourself"
},
'payload': formData,
'method': 'post'
};
var url = "https://api.tcgplayer.com/token";
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
cache.put(CACHE_KEY, response.getContentText(), 1728000);
return response;
}
function getTokenCache() {
var cached = JSON.parse(cache.get(CACHE_KEY));
// if cache is null or if the token has expired, request a new one
if (cached != null && Date.now() < Date.parse(cached[".expires"])) {
console.log('Token is still valid, returning cached token');
return cached;
}
if (cached == null) {
console.log('Cache key is unset');
}
return refreshToken();
}
function getPriceCache() {
var cached = JSON.parse(cache.get(PRICE_KEY));
if (cached != null) {
console.log('Price cache is still valid, returning cache');
return cached;
}
if (cached == null) {
// We'll expire the cache in 24 hours
return {}
}
}
function getProductCache() {
var cached = JSON.parse(cache.get(PRODUCT_KEY));
if (cached != null) {
console.log('Product cache is still valid, returning cache');
return cached;
}
if (cached == null) {
return {}
}
}
function getPriceCacheCount() {
var cached = JSON.parse(cache.get(PRICE_KEY));
if (cached != null) {
return Object.keys(cached).length;
}
return 0;
}
function getOptions(tokenCache) {
var options = {
'headers': {
'User-Agent': "update this yourself",
'Accept': 'application/json',
'Authorization': 'bearer ' + tokenCache["access_token"]
}
}
return options;
}
function test() {
var tokenCache = getTokenCache();
var product = "Battlebond Booster Box";
var product_Id = queryForProductId(product);
console.log(product_Id);
console.log(queryForPrice(product_Id));
return tokenCache["access_token"];
}
function queryForProductId(product) {
var tokenCache = getTokenCache();
var productCache = getProductCache();
if (product in productCache) {
return productCache[product]
}
var url = "https://api.tcgplayer.com/catalog/products?categoryId=1&limit=25&productName=" + encodeURI(product);
var options = getOptions(tokenCache);
var response = UrlFetchApp.fetch(url, options);
response = JSON.parse(response.getContentText());
var productId = response.results[0].productId;
productCache[product] = productId;
cache.put(PRODUCT_KEY, JSON.stringify(productCache), 31556952);
return productId;
}
function queryForPrice(productId) {
var tokenCache = getTokenCache();
var priceCache = getPriceCache();
if (productId in priceCache) {
return priceCache[productId];
}
var url = "https://api.tcgplayer.com/pricing/product/" + productId;
var options = getOptions(tokenCache);
var response = UrlFetchApp.fetch(url, options);
response = JSON.parse(response.getContentText());
var price = response.results.filter(res => res.subTypeName == "Normal")[0].marketPrice;
priceCache[productId] = price;
cache.put(PRICE_KEY, JSON.stringify(priceCache), 86000);
return price
}
function queryForGroups() {
var tokenCache = getTokenCache();
//cache.remove(GROUP_KEY);
var groupCache = JSON.parse(cache.get(GROUP_KEY));
if (groupCache != null){
return groupCache;
}
// update groupCache when expires
if (groupCache == null) {
groupCache = {
'last_updated': Date.now(),
'groups': {}
};
}
var url = "https://api.tcgplayer.com/catalog/groups?categoryId=1&hasSealed=true&sortOrder=groupId&limit=100";
var options = {
'headers': {
'User-Agent': "update this yourself",
'Accept': 'application/json',
'Authorization': 'bearer ' + tokenCache["access_token"]
}
}
//console.log(options);
// make first request to determine number of pages, then make repeated requests until all results are obtained
var response = UrlFetchApp.fetch(url, options);
response = JSON.parse(response.getContentText());
var offset = 0;
while(response.totalItems > Object.keys(groupCache.groups).length) {
response.results.forEach(element => groupCache.groups[element.name] = element.groupId)
// Ensure first page is in array, then continue with offset
offset = offset + 100;
if (offset < response.totalItems) {
response = UrlFetchApp.fetch(url + '&offset=' + offset, options);
response = JSON.parse(response.getContentText());
}
}
cache.put(GROUP_KEY, groupCache, 604800);
console.log(groupCache.groups);
}
function printToken() {
var cached = JSON.parse(cache.get(CACHE_KEY));
var sheet = SpreadsheetApp.getActiveSheet();
console.log(cached);
console.log(cached["access_token"]);
console.log(cached[".expires"]);
}
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
getTokenCache();
var entries = [{
name : "Refresh",
functionName : "refreshLastUpdate"
}];
sheet.addMenu("Refresh", entries);
};
function refreshLastUpdate() {
SpreadsheetApp.getActiveSpreadsheet().getRange('N2').setValue(new Date().toTimeString());
}
@freshyjmp
Copy link
Author

Obviously not production grade but it helps for tracking some products. One could probably go nuts with making the caching more elegant or batching requests but it works enough for the few times of year I'd bother looking at the spreadsheet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment