Last active
April 14, 2022 13:47
-
-
Save bangingheads/c49756ff71b8fc337f2abf16c46a03f7 to your computer and use it in GitHub Desktop.
Using Cloudflare Workers to Make Requests to Riot Games API
This file contains 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 Workers Script to make request to the Riot Games API | |
By: BangingHeads | |
Supports GET Requests | |
Supports Path and GET Parameters as GET Parameters | |
Example path: https://example.bangingheads.workers.dev/api/?region=na1&endpoint=/lol/summoner/v4/summoners/by-name/{summonerName}&summonerName=Headbang | |
Use Guide on Hextech Docs (https://hextechdocs.dev) if you need more help | |
*/ | |
// Your Riot Games API Key | |
const API_KEY = 'RGAPI-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'; | |
// The path to use, default /api/ | |
// If you do more to this script you potentially could want multiple paths | |
const API_ENDPOINT = '/api/'; | |
// Time in seconds to cache responses | |
// You may want lower or higher depending on how real time you need info | |
const CACHE_TIME = 600; | |
// Array of origins allowed, use ["*"] for all origins | |
// or full domain https://www.google.com | |
const ALLOWED_ORIGINS = ["https://www.google.com"] | |
// Don't modify below unless you know what you are doing | |
// Creates URL Query string from Object p1=1&p2=2 | |
const createQueryParams = params => | |
Object.keys(params) | |
.map(k => `${k}=${encodeURI(params[k])}`) | |
.join('&'); | |
async function handleRequest(request) { | |
const url = new URL(request.url); | |
// Reject unauthorized origins to avoid wasting API Calls | |
if (request.headers.get('Origin') !== null && request.headers.get('Origin') !== url.origin && !ALLOWED_ORIGINS.includes(request.headers.get('Origin')) && !ALLOWED_ORIGINS.includes("*")) { | |
return new Response("{'error': 'Origin not allowed'}", null); | |
} | |
let endpoint = url.searchParams.get('endpoint'); | |
if (endpoint == null || endpoint == "") { | |
return new Response("{'error': 'Missing endpoint'}", null); | |
} | |
const re = /{(\w+)}/g; | |
const params = [...endpoint.matchAll(re)]; | |
const reserved = ["region", "endpoint"]; | |
// Replace path parameters with GET parameters | |
for (const match of params) { | |
if (url.searchParams.get(match[1]) == null) { | |
return new Response(`{'error': 'Missing parameter: ${match[1]}'}`, null); | |
} | |
endpoint = endpoint.replace(match[0], encodeURI(url.searchParams.get(match[1]))); | |
reserved.push(match[1]); | |
} | |
let region = url.searchParams.get('region'); | |
if (region == null || region == "") { | |
return new Response("{'error': 'Missing region'}", null); | |
} | |
let fullUrl = `https://${region}.api.riotgames.com${endpoint}`; | |
// Add leftover get parameters | |
const getParams = {}; | |
for (const [key, value] of url.searchParams) { | |
if (!reserved.includes(key)) { | |
getParams[key] = value; | |
} | |
} | |
let reqParams = createQueryParams(getParams); | |
if (reqParams !== "") { | |
fullUrl = `${fullUrl}?${reqParams}`; | |
} | |
riotRequest = new Request(fullUrl, request); | |
riotRequest.headers.set('X-Riot-Token', API_KEY); | |
response = await fetch(riotRequest, { | |
cf: { | |
cacheTtl: CACHE_TIME, | |
cacheEverything: true, | |
} | |
}); | |
// Recreate the response so we can modify the headers | |
response = new Response(response.body, response); | |
// Set CORS headers | |
response.headers.set('Access-Control-Allow-Origin', request.headers.get('Origin')); | |
// Append to/Add Vary header so browser will cache response correctly | |
response.headers.append('Vary', 'Origin'); | |
return response; | |
} | |
// Handle Pre-flight OPTIONS calls for CORS | |
function handleOptions(request) { | |
let headers = request.headers; | |
let origin = ""; | |
if ( | |
headers.get('Origin') !== null && | |
headers.get('Access-Control-Request-Method') !== null && | |
headers.get('Access-Control-Request-Headers') !== null | |
) { | |
if (ALLOWED_ORIGINS.includes(headers.get('Origin')) || ALLOWED_ORIGINS.includes("*")) { | |
origin = headers.get('Origin'); | |
} | |
// Handle CORS pre-flight request. | |
let respHeaders = { | |
'Access-Control-Allow-Origin': origin, | |
'Access-Control-Allow-Methods': 'GET,HEAD,OPTIONS', | |
'Access-Control-Max-Age': '86400', | |
'Access-Control-Allow-Headers': request.headers.get('Access-Control-Request-Headers'), | |
}; | |
return new Response(null, { | |
headers: respHeaders, | |
}); | |
} else { | |
// Handle standard OPTIONS request. | |
// If you want to allow other HTTP Methods, you can do that here. | |
return new Response(null, { | |
headers: { | |
Allow: 'GET, HEAD, OPTIONS', | |
}, | |
}); | |
} | |
} | |
addEventListener('fetch', event => { | |
const request = event.request; | |
const url = new URL(request.url); | |
if (url.pathname.startsWith(API_ENDPOINT)) { | |
if (request.method === 'OPTIONS') { | |
// Handle CORS preflight requests | |
event.respondWith(handleOptions(request)); | |
} else if (request.method === 'GET' || request.method === 'HEAD') { | |
// Handle requests to the API server | |
event.respondWith(handleRequest(request)); | |
} else { | |
event.respondWith( | |
new Response(null, { | |
status: 405, | |
statusText: 'Method Not Allowed', | |
}) | |
); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment