Team Ai
Apppublic

cosmoEagle/leetcode-api

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.ts277 linesDownload Raw Back to src
1import express, { NextFunction, Response } from 'express';2import cors from 'cors';3import rateLimit from 'express-rate-limit';4import * as leetcode from './leetCode';5import { FetchUserDataRequest } from './types';6import apicache from 'apicache';7import axios from 'axios';8import {9  userContestRankingInfoQuery,10  discussCommentsQuery,11  discussTopicQuery,12  userProfileUserQuestionProgressV2Query,13  skillStatsQuery,14  getUserProfileQuery,15  userProfileCalendarQuery,16  officialSolutionQuery,17  dailyQeustion,18} from './GQLQueries/newQueries';19 20const app = express();21let cache = apicache.middleware;22const API_URL = process.env.LEETCODE_API_URL || 'https://leetcode.com/graphql';23 24const limiter = rateLimit({25  windowMs: 60 * 60 * 1000, // 1 hour26  limit: 60,27  standardHeaders: 'draft-7',28  legacyHeaders: false,29  message: 'Too many request from this IP, try again in 1 hour',30});31 32app.use(cache('5 minutes'));33app.use(cors()); //enable all CORS request34app.use(limiter); //limit to all API35app.use((req: express.Request, _res: Response, next: NextFunction) => {36  console.log('Requested URL:', req.originalUrl);37  next();38});39 40async function queryLeetCodeAPI(query: string, variables: any) {41  try {42    const response = await axios.post(API_URL, { query, variables });43    if (response.data.errors) {44      throw new Error(response.data.errors[0].message);45    }46    return response.data;47  } catch (error) {48    if (error.response) {49      throw new Error(`Error from LeetCode API: ${error.response.data}`);50    } else if (error.request) {51      throw new Error('No response received from LeetCode API');52    } else {53      throw new Error(`Error in setting up the request: ${error.message}`);54    }55  }56}57 58app.get('/', (_req, res) => {59  res.json({60    apiOverview:61      'Welcome to the Alfa-Leetcode-API! Alfa-Leetcode-Api is a custom solution born out of the need for a well-documented and detailed LeetCode API. This project is designed to provide developers with endpoints that offer insights into a user"s profile, badges, solved questions, contest details, contest history, submissions, and also daily questions, selected problem, list of problems.',62    apiEndpointsLink:63      'https://github.com/alfaarghya/alfa-leetcode-api?tab=readme-ov-file#endpoints-',64    routes: {65      userDetails: {66        description:67          'Endpoints for retrieving detailed user profile information on Leetcode.',68        Method: 'GET',69        '/:username': 'Get your leetcodevis profile Details',70        '/:username/badges': 'Get your badges',71        '/:username/solved': 'Get total number of question you solved',72        '/:username/contest': 'Get your contest details',73        '/:username/contest/history': 'Get all contest history',74        '/:username/submission': 'Get your last 20 submission',75        '/:username/acSubmission': 'Get your last 20 accepted submission',76        '/:username/calendar': 'Get your submission calendar',77        '/userProfile/:username': 'Get full profile details in one call',78        '/userProfileCalendar?username=yourname&year=2024':79          'Get your calendar details with year',80        '/languageStats?username=yourname': 'Get the language stats of a user',81        '/userProfileUserQuestionProgressV2/:userSlug':82          'Get your question progress',83        '/skillStats/:username': 'Get your skill stats',84      },85      contest: {86        description:87          'Endpoints for retrieving contest ranking and performance data.',88        Method: 'GET',89        '/userContestRankingInfo/:username': 'Get user contest ranking info',90      },91      discussion: {92        description: 'Endpoints for fetching discussion topics and comments.',93        Method: 'GET',94        '/trendingDiscuss?first=20': 'Get top 20 trending discussions',95        '/discussTopic/:topicId': 'Get discussion topic',96        '/discussComments/:topicId': 'Get discussion comments',97      },98      problems: {99        description:100          'Endpoints for fetching problem-related data, including lists, details, and solutions.',101        Method: 'GET',102        singleProblem: {103          '/select?titleSlug=two-sum': 'Get selected Problem',104          '/daily': 'Get daily Problem',105          '/dailyQuestion': 'Get raw daily question',106        },107        problemList: {108          '/problems': 'Get list of 20 problems',109          '/problems?limit=50': 'Get list of some problems',110          '/problems?tags=array+math': 'Get list problems on selected topics',111          '/problems?tags=array+math+string&limit=5':112            'Get list some problems on selected topics',113          '/officialSolution?titleSlug=two-sum':114            'Get official solution of selected problem',115        },116      },117    },118  });119});120 121app.get('/officialSolution', async (req, res) => {122  const { titleSlug } = req.query;123 124  if (!titleSlug) {125    return res.status(400).json({ error: 'Missing titleSlug query parameter' });126  }127  try {128    const data = await queryLeetCodeAPI(officialSolutionQuery, { titleSlug });129    return res.json(data);130  } catch (error) {131    return res.status(500).json({ error: error.message });132  }133});134 135app.get('/userProfileCalendar', async (req, res) => {136  const { username, year } = req.query;137 138  if (!username || !year || typeof year !== 'string') {139    return res140      .status(400)141      .json({ error: 'Missing or invalid username or year query parameter' });142  }143 144  try {145    const data = await queryLeetCodeAPI(userProfileCalendarQuery, {146      username,147      year: parseInt(year),148    });149    return res.json(data);150  } catch (error) {151    return res.status(500).json({ error: error.message });152  }153});154 155// Format data156const formatData = (data: any) => {157  return {158    totalSolved: data.matchedUser.submitStats.acSubmissionNum[0].count,159    totalSubmissions: data.matchedUser.submitStats.totalSubmissionNum,160    totalQuestions: data.allQuestionsCount[0].count,161    easySolved: data.matchedUser.submitStats.acSubmissionNum[1].count,162    totalEasy: data.allQuestionsCount[1].count,163    mediumSolved: data.matchedUser.submitStats.acSubmissionNum[2].count,164    totalMedium: data.allQuestionsCount[2].count,165    hardSolved: data.matchedUser.submitStats.acSubmissionNum[3].count,166    totalHard: data.allQuestionsCount[3].count,167    ranking: data.matchedUser.profile.ranking,168    contributionPoint: data.matchedUser.contributions.points,169    reputation: data.matchedUser.profile.reputation,170    submissionCalendar: JSON.parse(data.matchedUser.submissionCalendar),171    recentSubmissions: data.recentSubmissionList,172    matchedUserStats: data.matchedUser.submitStats,173  };174};175 176app.get('/userProfile/:id', async (req, res) => {177  const user = req.params.id;178 179  try {180    const data = await queryLeetCodeAPI(getUserProfileQuery, {181      username: user,182    });183    if (data.errors) {184      res.send(data);185    } else {186      res.send(formatData(data.data));187    }188  } catch (error) {189    res.send(error);190  }191});192 193const handleRequest = async (res: Response, query: string, params: any) => {194  try {195    const data = await queryLeetCodeAPI(query, params);196    res.json(data);197  } catch (error) {198    res.status(500).json({ error: error.message });199  }200};201app.get('/dailyQuestion', (_, res) => {202  handleRequest(res, dailyQeustion, {});203});204 205app.get('/skillStats/:username', (req, res) => {206  const { username } = req.params;207  handleRequest(res, skillStatsQuery, { username });208});209 210app.get('/userProfileUserQuestionProgressV2/:userSlug', (req, res) => {211  const { userSlug } = req.params;212  handleRequest(res, userProfileUserQuestionProgressV2Query, { userSlug });213});214 215app.get('/discussTopic/:topicId', (req, res) => {216  const topicId = parseInt(req.params.topicId);217  handleRequest(res, discussTopicQuery, { topicId });218});219 220app.get('/discussComments/:topicId', (req, res) => {221  const topicId = parseInt(req.params.topicId);222  const {223    orderBy = 'newest_to_oldest',224    pageNo = 1,225    numPerPage = 10,226  } = req.query;227  handleRequest(res, discussCommentsQuery, {228    topicId,229    orderBy,230    pageNo,231    numPerPage,232  });233});234 235app.get('/userContestRankingInfo/:username', (req, res) => {236  const { username } = req.params;237  handleRequest(res, userContestRankingInfoQuery, { username });238});239 240//get the daily leetCode problem241app.get('/daily', leetcode.dailyProblem);242 243//get the selected question244app.get('/select', leetcode.selectProblem);245 246//get list of problems247app.get('/problems', leetcode.problems);248 249//get 20 trending Discuss250app.get('/trendingDiscuss', leetcode.trendingCategoryTopics);251 252app.get('/languageStats', leetcode.languageStats);253 254// Construct options object on all user routes.255app.use(256  '/:username*',257  (req: FetchUserDataRequest, _res: Response, next: NextFunction) => {258    req.body = {259      username: req.params.username,260      limit: req.query.limit,261    };262    next();263  }264);265 266//get user profile details267app.get('/:username', leetcode.userData);268app.get('/:username/badges', leetcode.userBadges);269app.get('/:username/solved', leetcode.solvedProblem);270app.get('/:username/contest', leetcode.userContest);271app.get('/:username/contest/history', leetcode.userContestHistory);272app.get('/:username/submission', leetcode.submission);273app.get('/:username/acSubmission', leetcode.acSubmission);274app.get('/:username/calendar', leetcode.calendar);275 276export default app;277