If you have ever been on a job hunt for a software developer position, you would have come across the so-called LeetCode style interviews. Despite the fact that most of us don’t have to at our actual job, that is how most coding/technical interviews are conducted at big tech companies like Google and Microsoft. Yes, even at the likes of (except for Stripe, because they are cool) and startups. invert a Binary Tree unicorns In this post, I’ll be writing about the thought process of how I came about building and deploying a very simple JavaScript app for free with . If you simply want to deploy and use the app on your own, check out the repository . Cloudflare Worker here TL;DR How to get the Daily LeetCoding Challenge question using LeetCode API Creating a Todoist task using Todoist API Schedule our app to run daily using Cloudflare Worker ScheduledEvent API How to test a Cloudflare Worker Cron trigger locally with Miniflare Problem Statement For a year now, I have been trying to make it a habit to solve the Daily LeetCoding Challenge (which I’m still struggling with). As I am using as my main productivity tool of choice, I have a daily task that looks just like this: Todoist As a lazy person, having to check every time I want to practice is too much of a hassle. So then I thought, why not just sync the Daily LeetCoding Challenge to my Todoist every day? leetcode.com Requirements Let’s start by defining what I want the app to do: Get Daily LeetCoding Challenge question Ability to create a new task on my Todoist account Sync new Daily LeetCoding Challenge question on time The app has to sync on time for free every day Let’s start! LeetCode API Like any sane person would do, the first thing I did was to do some research. By research, I meant I started to Google for information. The first thing I did was to immediately Google for “leetcode API”, looking for the official API documentation. Official API documentation To my surprise, there wasn’t any official LeetCode API documentation available. While there is a couple of unofficial LeetCode API repositories on GitHub, I would rather not use any unofficial API due to reliability concerns (poorly maintained, outdated, etc.). The Good Ol’ DevTool inspection The second thing that immediately came to my mind was to inspect the network request being made while visiting the site . https://leetcode.com/problemset/all/ With this, I was able to figure out the exact API called to query for the Daily LeetCoding Challenge — done. Here’s the GraphQL request body: # HTTP POST to https://leetcode.com/graphql query questionOfToday { activeDailyCodingChallengeQuestion { date userStatus link question { acRate difficulty freqBar frontendQuestionId: questionFrontendId isFavor paidOnly: isPaidOnly status title titleSlug hasVideoSolution hasSolution topicTags { name id slug } } } } You can use the command below to try it out yourself: curl curl --request POST \ --url https://leetcode.com/graphql \ --header 'Content-Type: application/json' \ --data '{"query":"query questionOfToday {\n\tactiveDailyCodingChallengeQuestion {\n\t\tdate\n\t\tuserStatus\n\t\tlink\n\t\tquestion {\n\t\t\tacRate\n\t\t\tdifficulty\n\t\t\tfreqBar\n\t\t\tfrontendQuestionId: questionFrontendId\n\t\t\tisFavor\n\t\t\tpaidOnly: isPaidOnly\n\t\t\tstatus\n\t\t\ttitle\n\t\t\ttitleSlug\n\t\t\thasVideoSolution\n\t\t\thasSolution\n\t\t\ttopicTags {\n\t\t\t\tname\n\t\t\t\tid\n\t\t\t\tslug\n\t\t\t}\n\t\t}\n\t}\n}\n","operationName":"questionOfToday"}' Enough talking, let’s start to write some code that does exactly what we went through: // Just some constants const LEETCODE_API_ENDPOINT = 'https://leetcode.com/graphql' const DAILY_CODING_CHALLENGE_QUERY = ` query questionOfToday { activeDailyCodingChallengeQuestion { date userStatus link question { acRate difficulty freqBar frontendQuestionId: questionFrontendId isFavor paidOnly: isPaidOnly status title titleSlug hasVideoSolution hasSolution topicTags { name id slug } } } }` // We can pass the JSON response as an object to our createTodoistTask later. const fetchDailyCodingChallenge = async () => { console.log(`Fetching daily coding challenge from LeetCode API.`) const init = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: DAILY_CODING_CHALLENGE_QUERY }), } const response = await fetch(LEETCODE_API_ENDPOINT, init) return response.json() } Task “Get Daily LeetCoding Challenge question” — checked. Todoist API Like what we did in the previous step, I was able to find the for Todoist. Typically, the first section that I always look for in API documentation is the section, especially when you want to perform create/update/delete operations on an app. official API documentation Authorization In short, authorization was pretty straightforward for Todoist: Get your API token Whenever you make a request, attach to your HTTP request header Authorization: Bearer xxx-your-todoist-api-token-xxx Here’s an example of what the curl command to create a new task on Todoist would look like: curl --request POST \ --url 'https://api.todoist.com/rest/v1/tasks?=' \ --header 'Authorization: Bearer xxx-your-todoist-api-token-xxx' \ --header 'Content-Type: application/json' \ --data '{ "content": "Buy a jar of peanut butter", "due_string": "Today" }' Code Writing a function that does what we said is relatively easy, it looks something like this: const TODOIST_API_ENDPOINT = "https://api.todoist.com/rest/v1"; // Passing in the `question` object from fetchDailyCodingChallenge function const createTodoistTask = async (question) => { const questionInfo = question.data.activeDailyCodingChallengeQuestion; const questionTitle = questionInfo.question.title; const questionDifficulty = questionInfo.question.difficulty; const questionLink = `https://leetcode.com${questionInfo.link}`; console.log(`Creating Todoist task with title ${questionTitle}.`); const body = { content: `[${questionTitle}](${questionLink})`, description: `Difficulty: ${questionDifficulty}`, due_string: "Today", priority: 4, }; const init = { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", Authorization: `Bearer ${TODOIST_API_TOKEN}`, // Set at environment variable }, }; const response = await fetch(`${TODOIST_API_ENDPOINT}/tasks`, init); return response.json(); }; Task “Create a new task on my Todoist account” — done. Cloudflare Worker And we’re down to our one final task — running/automating the 2 tasks above every day, for free. The first thing that came to my mind was Cron job. So, I immediately started looking for free solutions on the Internet. After spending a couple of hours doing some homework, I came across Cloudflare Worker, and I figured to give them a try. It runs on V8 JavaScript, not Node.js This is probably one of the most common misconceptions . As the worker’s environment is not in Node.js, a lot of packages (e.g. ) that are running on Node.js would simply not work. about Cloudflare Worker npm install some-node-package Tip: Check out the supported packages and libraries . here Lucky for us, we only need to use the JavaScript built-in API. fetch More code Starting a Cloudflare Worker project is dead simple ( ), basically: reference Install the Wrangler CLI using npm install -g @cloudflare/wrangler Run wrangler generate <your-project-name> <worker-template> The entry point is function. For our use case, we will be using the API where we simply have to change our event from to addEventListener ScheduledEvent "fetch" "scheduled" Let’s stitch everything together: // Move the constants to const.js const syncLeetCodeCodingChallenge = async (event) => { const question = await fetchDailyCodingChallenge(); await createTodoistTask(question); }; addEventListener("scheduled", (event) => { // Change 'fetch' to 'scheduled' event.waitUntil(syncLeetCodeCodingChallenge(event)); }); Next, we would simply need to modify the wrangler.toml as below: name = "<your-project-name>" type = "webpack" ... [triggers] crons = ["1 0 * * *"] With the setting above, the worker will run every day at and sync the Daily LeetCoding Challenge to your Todoist. 00:01 UTC That’s all! Moving on to testing. How to test Cloudflare workers locally In order to try out the Cron triggers locally, we would need to install the . After installation, you may run your worker using: Miniflare CLI # At terminal 1 miniflare # At terminal 2 curl "http://localhost:8787/.mf/scheduled" If you see a new task is created on your Todoist, you have made it! Deployment No side project is ever done without hosting it. To deploy the app on your own immediately, check out the and use the button. If you’re interested in the know-how: project repository “Deploy with Workers” Create a Cloudflare account. Add using . You may find the newly added secret under 'Cloudflare Worker' → 'Settings' → 'Variables'. You can get your Todoist API token . TODOIST_API_TOKEN wrangler secret put TODOIST_API_TOKEN here Optional: This is only required for . Add into your GitHub repository secrets. You can create your API token from using the template. Wrangler actions CF_API_TOKEN https://dash.cloudflare.com/profile/api-tokens Edit Cloudflare Workers Finally, to publish any new changes to your Cloudflare Worker, run wrangler publish And we are finally done! Closing Thoughts Finally, there’s a lot more that we could have done, e.g.: Handling unanswered questions from previous days Making the app configurable/customizable for users Add tags to our task Allowing users to create a random LeetCode question as a task based on question tag I’m going to leave these features out for another day. While there is a lot of hate on coding interviews as such, I personally look at it this way — by learning some brain teasers, you probably get paid a lot more, so why not? It is really a matter of perspective. If you happen to enjoy doing them, that is even better. Personally, I don’t find as much joy doing LeetCode questions. Rather, I work on LeetCode problems as if I am lifting weights at the gym. While I don’t enjoy lifting weights, I do like reaping the benefits of it. That’s all for today. Let me know what are you building with Cloudflare Worker!