前端笔记:获取leetcode题目
原仓库代码:/select?titleSlug=selected-question 这个端点函数的调用关系是?
The /select?titleSlug=selected-question
endpoint in the alfaarghya/alfa-leetcode-api
repository is implemented using a GraphQL query defined in src/GQLQueries/selectProblem.ts
. The query fetches detailed information about a specific question based on the titleSlug
.
Here is the source code for the implementation.
The code in src/GQLQueries
is imported and used in src/GQLQueries/index.ts
. You can view the details here.
解释export { default as selectProblemQuery } from ‘./selectProblem’;
This line of code in src/GQLQueries/index.ts
re-exports the default export from the ./selectProblem
module and names it selectProblemQuery
. This allows other modules to import selectProblemQuery
directly from src/GQLQueries/index.ts
instead of importing from ./selectProblem
directly.
export const selectProblem = (req: Request, res: Response) => {
const title = req.query.titleSlug as string;
if (title !== undefined) {
controllers.fetchSingleProblem(
res,
formatUtils.formatQuestionData,
gqlQueries.selectProblemQuery,
title
);
} else {
res.status(400).json({
error: 'Missing or invalid query parameter: titleSlug',
solution: 'put query after select',
example: 'localhost:3000/select?titleSlug=two-sum',
});
}
};
This code defines and exports a function named selectProblem
which acts as a route handler for an Express.js application. Here’s what it does:
- It extracts the
titleSlug
query parameter from the request (req
). - If
titleSlug
is defined, it calls thefetchSingleProblem
function from thecontrollers
module, passing it the response object (res
), a format function (formatUtils.formatQuestionData
), a GraphQL query (gqlQueries.selectProblemQuery
), and thetitleSlug
. - If
titleSlug
is not defined, it responds with a 400 status and a JSON error message indicating the missing or invalid query parameter. The response includes an example of the correct usage.
import { Response } from 'express';
import { DailyProblemData, SelectProblemData } from '../types';
const fetchSingleProblem = async (
res: Response,
formatData: (data: DailyProblemData & SelectProblemData) => void,
query: string,
titleSlug: string | null
) => {
try {
const response = await fetch('https://leetcode.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Referer: 'https://leetcode.com',
},
body: JSON.stringify({
query: query,
variables: {
titleSlug, //search question using titleSlug
},
}),
});
const result = await response.json();
if (result.errors) {
return res.send(result);
}
return res.json(formatData(result.data));
} catch (err) {
console.error('Error: ', err);
return res.send(err);
}
};
export default fetchSingleProblem;
This code defines and exports an asynchronous function fetchSingleProblem
which performs the following actions:
- Imports
Response
fromexpress
and two types,DailyProblemData
andSelectProblemData
, from../types
. - The function
fetchSingleProblem
takes four parameters:res
(Express response object),formatData
(a function to format the fetched data),query
(a GraphQL query string), andtitleSlug
(the title slug of the problem). - It sends a POST request to the LeetCode GraphQL API with the provided query and titleSlug.
- If the request is successful and there are no errors, it formats the data using
formatData
and sends it in the response. - If an error occurs, it logs the error and sends the error in the response.
总结
要实现一个独立的 /select?titleSlug=selected-question
端点,下面是一个完整的项目结构、运行和测试步骤。
项目结构
my-leetcode-api/
├── src/
│ ├── GQLQueries/
│ │ ├── selectProblem.ts
│ ├── controllers/
│ │ ├── fetchSingleProblem.ts
│ │ └── problemController.ts
│ ├── routes/
│ │ └── problemRoutes.ts
│ ├── types/
│ │ └── index.ts
│ ├── app.ts
│ └── server.ts
├── package.json
├── tsconfig.json
└── README.md
代码实现
src/GQLQueries/selectProblem.ts
const query = `#graphql
query selectProblem($titleSlug: String!) {
question(titleSlug: $titleSlug) {
questionId
questionFrontendId
boundTopicId
title
titleSlug
content
translatedTitle
translatedContent
isPaidOnly
difficulty
likes
dislikes
isLiked
similarQuestions
exampleTestcases
contributors {
username
profileUrl
avatarUrl
}
topicTags {
name
slug
translatedName
}
companyTagStats
codeSnippets {
lang
langSlug
code
}
stats
hints
solution {
id
canSeeDetail
paidOnly
hasVideoSolution
paidOnlyVideo
}
status
sampleTestCase
metaData
judgerAvailable
judgeType
mysqlSchemas
enableRunCode
enableTestMode
enableDebugger
envInfo
libraryUrl
adminUrl
challengeQuestion {
id
date
incompleteChallengeCount
streakCount
type
}
note
}
}`;
export default query;
src/controllers/fetchSingleProblem.ts
import { Response } from 'express';
import { DailyProblemData, SelectProblemData } from '../types';
const fetchSingleProblem = async (
res: Response,
formatData: (data: DailyProblemData & SelectProblemData) => void,
query: string,
titleSlug: string | null
) => {
try {
const response = await fetch('https://leetcode.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Referer: 'https://leetcode.com',
},
body: JSON.stringify({
query: query,
variables: {
titleSlug,
},
}),
});
const result = await response.json();
if (result.errors) {
return res.send(result);
}
return res.json(formatData(result.data));
} catch (err) {
console.error('Error: ', err);
return res.send(err);
}
};
export default fetchSingleProblem;
src/controllers/problemController.ts
import { Request, Response } from 'express';
import fetchSingleProblem from './fetchSingleProblem';
import { formatQuestionData } from '../utils/formatUtils';
import selectProblemQuery from '../GQLQueries/selectProblem';
export const selectProblem = (req: Request, res: Response) => {
const title = req.query.titleSlug as string;
if (title !== undefined) {
fetchSingleProblem(
res,
formatQuestionData,
selectProblemQuery,
title
);
} else {
res.status(400).json({
error: 'Missing or invalid query parameter: titleSlug',
solution: 'put query after select',
example: 'localhost:3000/select?titleSlug=two-sum',
});
}
};
src/routes/problemRoutes.ts
import express from 'express';
import { selectProblem } from '../controllers/problemController';
const router = express.Router();
router.get('/select', selectProblem);
export default router;
src/types/index.ts
export interface DailyProblemData {
// Define your DailyProblemData properties here
}
export interface SelectProblemData {
// Define your SelectProblemData properties here
}
src/app.ts
import express from 'express';
import problemRoutes from './routes/problemRoutes';
const app = express();
app.use(express.json());
app.use('/api/problems', problemRoutes);
export default app;
src/server.ts
import app from './app';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
运行项目
-
初始化项目:
npm init -y npm install express typescript ts-node @types/node @types/express
-
创建
tsconfig.json
文件:{ "compilerOptions": { "target": "ES6", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }, "include": ["src"], "exclude": ["node_modules"] }
-
在
package.json
中添加脚本:"scripts": { "start": "ts-node src/server.ts" }
-
运行项目:
npm start
测试
-
使用 Postman 或 cURL 测试端点:
curl -X GET "http://localhost:3000/api/problems/select?titleSlug=two-sum"
-
确保返回正确的数据格式和内容。
以上便是实现独立的 /select?titleSlug=selected-question
端点的完整项目结构、代码实现、运行步骤和测试方法。