原仓库代码:/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) {questionIdquestionFrontendIdboundTopicIdtitletitleSlugcontenttranslatedTitletranslatedContentisPaidOnlydifficultylikesdislikesisLikedsimilarQuestionsexampleTestcasescontributors {usernameprofileUrlavatarUrl}topicTags {nameslugtranslatedName}companyTagStatscodeSnippets {langlangSlugcode}statshintssolution {idcanSeeDetailpaidOnlyhasVideoSolutionpaidOnlyVideo}statussampleTestCasemetaDatajudgerAvailablejudgeTypemysqlSchemasenableRunCodeenableTestModeenableDebuggerenvInfolibraryUrladminUrlchallengeQuestion {iddateincompleteChallengeCountstreakCounttype}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
端点的完整项目结构、代码实现、运行步骤和测试方法。