Skip to content

Instantly share code, notes, and snippets.

@mikaeldui
Last active February 2, 2022 18:02
Show Gist options
  • Save mikaeldui/1df977bfffc18ebc4c02ac3ee164d8bc to your computer and use it in GitHub Desktop.
Save mikaeldui/1df977bfffc18ebc4c02ac3ee164d8bc to your computer and use it in GitHub Desktop.
Riot Games API proxy on Cloudflare Workers
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
/**
* Many more examples available at:
* https://developers.cloudflare.com/workers/examples
* @param {Request} request
* @returns {Promise<Response>}
*/
async function handleRequest(event) {
const request = event.request
const cacheUrl = new URL(request.url)
const cacheKey = new Request(cacheUrl.toString(), request)
let cache = caches.default
let response = await cache.match(cacheKey)
if (response) {
console.log(`Cache hit for: ${request.url}.`)
return response
} else {
console.log(`Response for request url: ${request.url} not present in cache. Fetching and caching request.`)
try {
response = await sendToRiot(request)
// Clone the response so that it's no longer immutable
response = new Response(response.body, response)
if (response.status == 200 && // Only cache 200 responses (not rate limits etc)
!request.url.endsWith('lol/spectator/v4/featured-games')) { // Don't cache featured games
response.headers.set("Cache-Control", "max-age=600, stale-while-revalidate=60, stale-if-error=86400, must-revalidate")
// NOTE: waitUntil does NOT block / wait
event.waitUntil(cache.put(cacheKey, response.clone()))
}
} catch (e) {
return new Response(JSON.stringify({ error: e.message }), { status: 500 })
}
}
if (request.headers.get('CF-Connecting-IP') == DEVELOPER_IP) {
// Allow localhost etc.
response.headers.set("Access-Control-Allow-Origin", "*")
// Allow whatever headers are set (CORS).
response.headers.set("Access-Control-Allow-Headers", request.headers.get("Access-Control-Request-Headers"))
} else {
response.headers.delete("Access-Control-Allow-Origin")
response.headers.delete("Access-Control-Allow-Methods")
response.headers.delete("Access-Control-Allow-Headers")
response.headers.delete("Access-Control-Expose-Headers")
}
// Create an identity TransformStream (a.k.a. a pipe).
// The readable side will become our new response body.
let { readable, writable } = new TransformStream()
// Start pumping the body. NOTE: No await!
response.body.pipeTo(writable)
return new Response(readable, response)
}
async function sendToRiot(request) {
const { pathname } = new URL(request.url)
// Assumes the path is in the format /euw1/lol/spectator/v4/featured-games. If /api/euw1/... change both 1's to 2's below.
const url = new URL("https://" + pathname.split("/")[1] + ".api.riotgames.com" + pathname.substring(pathname.indexOf('/', 1)))
console.log("Riot API URL: " + url.toString())
const newRequest = new Request(url.toString(), request)
newRequest.headers.set("X-Riot-Token", RIOT_TOKEN)
return await fetch(newRequest)
}
@mikaeldui
Copy link
Author

Set RIOT_TOKEN to your token and DEVELOPER_IP to your IP address, as environment variables in the worker settings.
Featured Games will bypass the CF cache.

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