Open edX Enhanced Staff Grader 模拟 BFF 指南:基于 JSON 数据存储的 Mock API 详解 📅 发布时间:2026/9/17 3:16:19 👁 浏览次数: Open edX Enhanced Staff Grader 模拟 BFF 指南基于 JSON 数据存储的 Mock API 详解【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform本文围绕 Open edXopenedx-platform仓库中 lms/djangoapps/ora_staff_grader/mock/README.md 展开完整讲解 ESGEnhanced Staff Grader增强型工作人员评分器模拟后端 BFFBackend-for-Frontend的设计思路、JSON 数据存储结构、全部 Mock 端点、交互式数据修改机制以及基于 Postman 的无头headless测试流程。读完本文你将能够独立启动并调用{lms-url}/api/ora_staff_grader/mock/{endpoint}系列端点读懂并编辑mock/data/下的四个 JSON 数据文件实现真实/模拟 BFF 的无缝切换并利用源码与测试用例验证端点的实际行为。一、什么是 ESG 与 Mock BFFESGEnhanced Staff Grader是 Open edX 中构建在 ORAOpen Response Assessment开放问答评估之上的一个应用用于简化工作人员对作业的人工评分流程。其 BFF 层负责服务 ESG 微前端MFE将前端请求聚合、打包后转发给edx-platform与edx-ora2见 lms/djangoapps/ora_staff_grader/README.md。而本文的主角——mock子应用lms/djangoapps/ora_staff_grader/mock/则是一个模拟版 BFF它在http(s)://{lms-url}/api/ora_staff_grader/mock/{endpoint}路径下提供与真实 BFF 形状一致的 Mock 端点使前端团队可以在不依赖真实 ORA 数据与edx-ora2服务的情况下独立完成 ESG 界面的开发、联调与验收。Mock 与真实 BFF 的关键差异只在一个 URL 片段上类型路径前缀数据来源真实 BFF{lms-url}/api/ora_staff_grader/{endpoint}edx-platformedx-ora2真实数据Mock BFF{lms-url}/api/ora_staff_grader/mock/{endpoint}mock/data/目录下的 JSON 文件由于路径结构完全平行见 mock/urls.py 与 urls.py 中path(mock/, include(...))的挂载方式只需通过配置基础 API 路径即可在真实与模拟版本之间切换无需改动任何前端调用逻辑。二、架构核心JSON 数据存储Mock 本质上是对一个JSON 数据存储JSON data store的包装器。所有关键数据都存放在lms/djangoapps/ora_staff_grader/mock/data/目录下共四个文件lms/djangoapps/ora_staff_grader/mock/data/ ├── course_metadata.json # 课程元数据按 ORA block location 索引 ├── ora_metadata.json # ORA 组件元数据rubric 等按 ORA block location 索引 ├── submissions.json # 提交数据评分状态、锁定状态、评分明细按 ora_location → submissionUUID 二级索引 └── responses.json # 学生作答内容文本 附件按 submissionUUID 索引数据一般以请求中携带的键通常是submissionUUID和/或ora_location进行分组。要增删改数据直接编辑对应的 JSON 文件即可——无需数据库迁移、无需重启特殊服务文件由请求时实时读取。2.1 course_metadata.json课程元数据{ block-a: { title: Defense against the dark arts, org: Hogwarts, number: DADA101, courseId: course-v1:HogwartsDADA1012021_Winter }, block-b: { title: Introduction to Time Travel, org: Oxford, number: TT101, courseId: course-v1:OxfordTT1012021_Winter } }顶层键即oraLocationORA 组件在课程中的 block location对应 mock/utils.py 中get_course_metadata(ora_location)的read_data_file(course_metadata.json)[ora_location]读取逻辑。字段title、org、number、courseId构成了 ESG 界面展示课程信息所需的完整元数据。2.2 ora_metadata.jsonORA 组件元数据该文件描述 ORA 组件本身的配置包括组件名称、类型individual个人作答 /team团队作答、提示语prompts、文本/文件上传应答配置以及完整的rubricConfig评分量规{ block-a: { name: Individual ORA, prompts: [pEnter a text/files response./p], type: individual, rubricConfig: { feedback_prompt: How would you grade this response?, feedback_default_text: I believe this response..., feedback: optional, criteria: [ { orderNum: 0, name: grammar, label: Grammar, prompt: How correct is the submitters grammar?, feedback: optional, options: [ {orderNum: 0, name: poor, label: Poor, explanation: Absolute rubbish, points: 0}, {orderNum: 1, name: good, label: Good, explanation: pretty good, points: 3}, {orderNum: 2, name: excellent, label: Excelent, explanation: Not absolute rubbish, points: 5} ] } ] }, textResponseConfig: optional, fileUploadResponseConfig: optional } }从源码结构可以推断rubricConfig直接为 ESG 前端渲染评分表单提供依据每个criteria项携带name、label、prompt、feedback与options列表每个option又包含orderNum、name、label、explanation和分值points这些字段与submissions.json中gradeData.criteria的结构一一对应模拟了工作人员按量规逐条打分的完整流程。2.3 responses.json学生作答内容responses.json按submissionUUID索引存放学生提交的正文textHTML 数组与附件files列表name、description、downloadUrl、size字段。例如SUBMISSION_ID-0下内置了 bmp、doc、docx、html、jpeg、jpg、ppt、pptx、tiff、txt、xls、xlsx 等多种格式的示例附件。注意fetch_response(submission_id)的默认实现是所有提交返回同一份默认应答见 mock/utils.py这正体现了 Mock 数据够用即可的简化原则。2.4 submissions.json提交与评分状态核心数据submissions.json是 Mock 中最核心的数据文件采用ora_location→submissionUUID两级索引{ block-a: { SUBMISSION_ID-0: { submissionUUID: SUBMISSION_ID-0, username: USERNAME-0, dateSubmitted: 1631215154955, score: {pointsEarned: 70, pointsPossible: 100}, gradeData: { showValidation: false, overallFeedback: , criteria: [ {orderNum: 0, name: grammar, selectedOption: excellent, feedback: test3} ], score: {pointsEarned: 0, pointsPossible: 100} }, gradeStatus: graded, lockStatus: unlocked }, SUBMISSION_ID-3: { submissionUUID: SUBMISSION_ID-3, username: USERNAME-3, dateSubmitted: 1631474354955, score: null, gradeData: null, gradeStatus: ungraded, lockStatus: in-progress } }, block-b: { TEAM_SUBMISSION_ID-0: { submissionUUID: TEAM_SUBMISSION_ID-0, teamName: TEAMNAME-0, dateSubmitted: 1631215154955, score: null, gradeData: null, gradeStatus: ungraded, lockStatus: in-progress } } }每个提交对象包含以下关键字段字段含义取值示例submissionUUID提交唯一标识SUBMISSION_ID-0username/teamName个人提交者用户名或团队名USERNAME-0/TEAMNAME-0dateSubmitted提交时间毫秒时间戳1631215154955score总分未评分时为null{pointsEarned: 70, pointsPossible: 100}gradeData评分明细量规逐条打分未评分时为null含criteria、overallFeedback、scoregradeStatus评分状态graded/ungradedlockStatus锁定状态unlocked/locked/in-progress从示例数据看block-a对应个人 ORASUBMISSION_ID-0~SUBMISSION_ID-4block-b对应团队 ORATEAM_SUBMISSION_ID-0~TEAM_SUBMISSION_ID-4两组数据刻意覆盖了已评分/未评分 × 已解锁/已锁定/进行中的全部状态组合为前端状态渲染提供了完备的测试样本。三、Mock 端点全览与源码实现Mock 的五个端点定义在 mock/urls.pyapp_name mock-ora-staff-grader视图实现在 mock/views.py。真实 BFF 端点与 Mock 端点一一对应只是路径中少了mock段。端点方法查询参数功能/api/ora_staff_grader/mock/initializeGEToraLocation返回应用初始状态课程元数据 ORA 元数据 提交列表/api/ora_staff_grader/mock/submissionGEToraLocation、submissionUUID获取单个提交含作答内容/api/ora_staff_grader/mock/submission/statusGEToraLocation、submissionUUID获取提交状态不含作答内容/api/ora_staff_grader/mock/submission/lockPOST / DELETEoraLocation、submissionUUID锁定 / 解锁提交/api/ora_staff_grader/mock/submission/gradePOSToraLocation、submissionUUID请求体为评分数据提交评分并写回数据存储3.1 initialize初始化应用状态InitializeViewmock/views.py读取oraLocation参数将courseMetadata、oraMetadata、submissions三项打包返回一次性为 ESG 前端提供渲染工作台所需的全部数据。这里调用的get_submissions(ora_location)有一个值得注意的细节列表场景下会pop掉每个提交的gradeData见 mock/utils.py即初始化列表不携带评分明细只有在单个提交的详情接口中才返回gradeData这与真实 BFF 的数据裁剪策略保持一致。3.2 submission获取单个提交SubmissionFetchView同时读取提交记录与作答内容返回四个字段{ gradeData: { ...: 评分明细 }, response: { ...: 学生作答内容 }, gradeStatus: graded, lockStatus: unlocked }3.3 submission/status只取状态SubmissionStatusFetchView与上者唯一区别是不包含response作答内容仅返回gradeStatus、lockStatus、gradeData适合前端用于轮询/刷新评分状态、判断是否显示作答面板等场景。3.4 submission/lock交互式锁定/解锁SubmissionLockView是体现简单交互性的典型端点POST将lockStatus置为in-progress并写回数据文件响应{lockStatus: in-progress}DELETE将lockStatus置为unlocked并写回响应{lockStatus: unlocked}。每次命中端点都会调用save_submission_update(ora_location, submission)将变更落盘到submissions.json。这意味着你可以通过读取更新后的 JSON 文件来验证调用结果也可以通过git checkout该文件一键还原到初始状态这是 Mock 相比真实后端最方便的开发调试特性。3.5 submission/grade写入评分UpdateGradeView接收请求体中的评分数据执行update_grade_data完成一次完整的评分闭环submission[gradeData] grade_data submission[gradeStatus] graded submission[lockStatus] unlocked submission[score] {pointsEarned: 70, pointsPossible: 100}注意其中写死了一个静态测试分数{pointsEarned: 70, pointsPossible: 100}注释明确标注 this is static test data即 Mock 评分总是返回 70/100 的固定得分——这是刻意为之的简化便于前端对评分结果做确定性断言。四、数据读写底层实现所有 Mock 数据的读写都集中在 mock/utils.py其根路径常量DATA_ROOT指向部署环境中的edx-platform/lms/djangoapps/ora_staff_grader/mock/data。核心函数包括read_data_file(file_name)读取 JSON 文件并反序列化update_data_file(file_name, update_key_path, update_value)按键路径update_key_path为逐层遍历的 key 列表更新单个值再以indent4格式写回文件保证人类可读、可 diffsave_submission_update(ora_location, submission)以[ora_location, submissionUUID]作为键路径调用update_data_file实现单条提交记录的原地更新。这套实现保证了编辑 JSON 即改数据、调用端点即写数据的双向可操作性也让 Mock 数据的变更始终处于git版本控制之下可随时对比与回滚。五、快速上手直连端点在 devstack 环境启动 LMS 后直接访问注意使用 devstack 的 lms 地址{devstack-url}/api/ora_staff_grader/mock/{endpoint}例如在浏览器或 curl 中请求初始化端点curl {devstack-url}/api/ora_staff_grader/mock/initialize?oraLocationblock-a即可拿到block-a对应的课程元数据、ORA 元数据含量规与提交列表不含gradeData。将oraLocation换成block-b则可体验团队 ORA 的数据。对于lock/grade等写操作端点调用后可打开 mock/data/submissions.json 检查对应submissionUUID记录的lockStatus、gradeStatus、gradeData是否已更新。六、Postman 无头测试流程除直连外仓库还附带了 Postman 集合用于对端点进行无头headless测试。完整的登录流程封装在lms.postman_collection.json位于 lms/djangoapps/ora_staff_grader/lms.postman_collection.json按以下步骤执行执行GET Login请求向{{protocol}}://{{lms_url}}/login发起 GET集合内的 test 脚本会读取响应中的csrftokenCookie 并写入环境变量var xsrfCookie postman.getResponseCookie(csrftoken); postman.setEnvironmentVariable(csrftoken, xsrfCookie.value);执行POST Login请求携带上一步生成的X-CSRFToken头以email{{user_email}}和password{{user_password}}表单数据调用{{protocol}}://{{lms_url}}/api/user/v1/account/login_session/完成 LMS 会话认证。配置环境变量按 mock 文档要求设置{{mock}} True真实 BFF 联调时置为False并配置{{protocol}}、{{lms_url}}、{{user_email}}、{{user_password}}等变量。运行 ESG 示例请求在ora_staff_grader.postman_collection.json中运行各端点示例请求验证 initialize / submission / lock / grade 等场景。文档同时提示由于{{mock}}变量控制着请求的基础路径是否包含mock段仅靠切换一个环境变量即可在模拟与真实端点之间来回切换无需修改任何请求定义。七、真实 BFF 与 Mock 的对照与切换真实 BFF 的路由挂载在 lms/djangoapps/ora_staff_grader/urls.py其中一行path(mock/, include(lms.djangoapps.ora_staff_grader.mock.urls)),将 Mock 子路由挂到了mock/前缀下。真实的 BFF 比 Mock 多出submission/batch/unlock批量解锁、submission/files获取作答附件、assessments/feedback反馈接口等能力且SubmissionLockView等真实实现会经过LockContestedError、XBlockInternalError等并发/内部错误处理对应 errors.py 与 constants.py 中的错误码。Mock 视图则刻意去掉了鉴权、错误分支与真实数据源只保留形状一致的响应结构——这正是它轻量、可预测、适合前端开发的原因。八、测试用例如何验证 Mock 行为仓库在 lms/djangoapps/ora_staff_grader/tests/ 下为整个 ESG 应用提供了测试套件test_views.py基于SharedModuleStoreTestCase APITestCase对视图层进行集成测试覆盖initialize、fetch-submission、lock、update-grade等视图测试基建BaseViewTest会构造课程、openassessment类型 XBlock 与StaffFactory工作人员账号并断言锁定竞争LockContestedError、非法oraLocationERR_BAD_ORA_LOCATION等错误路径test_data.py提供视图测试所需的结构化测试数据test_serializers.py验证 BFF 与edx-ora2之间序列化层的字段映射。这些测试一方面印证了端点的真实调用链路与参数约定另一方面也为 Mock 的返回结构如gradeStatus/lockStatus/gradeData三要素提供了可对照的行为基准。九、小结与扩展建议Open edX 的 Mock ESG BFF 用一个目录、四个 JSON 文件、五个 DRF 视图就完成了对整套评分工作流的前端支撑其核心价值有三路径平行、一键切换mock段的存在让真实/模拟端点切换成本趋近于零数据即代码、可视化调试所有状态变更都落在可读的 JSON 文件中git diff/git checkout即可完成验证与回滚覆盖状态全集内置的个人/团队提交样本覆盖了graded/ungraded × unlocked/locked/in-progress的各种组合天然适合前端边界场景开发。在此基础上你可以按需扩展在submissions.json中新增submissionUUID以模拟更多提交调整gradeData.criteria以匹配新的量规结构或在 mock/views.py 中按真实 BFF 的形状补全submission/files、submission/batch/unlock等端点的 Mock 版本让模拟服务与真实服务始终保持在可对比的同一水平线上。【免费下载链接】openedx-platformThe Open edX LMS Studio, powering education sites around the world!项目地址: https://gitcode.com/GitHub_Trending/ed/openedx-platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考