419 lines
13 KiB
JSON
419 lines
13 KiB
JSON
{
|
|
"info": {
|
|
"name": "Yimaru Dynamic Question Type Builder API",
|
|
"_postman_id": "f0f9c795-09aa-4f5a-9cc0-1f2fcb0f1b01",
|
|
"description": "Complete Postman collection for the dynamic question type builder feature, including catalog, validation, reusable type-definition CRUD, and question create/update using question_type_definition_id.",
|
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
|
},
|
|
"variable": [
|
|
{
|
|
"key": "baseUrl",
|
|
"value": "http://localhost:8080"
|
|
},
|
|
{
|
|
"key": "apiPrefix",
|
|
"value": "/api/v1"
|
|
},
|
|
{
|
|
"key": "token",
|
|
"value": ""
|
|
},
|
|
{
|
|
"key": "questionTypeDefinitionId",
|
|
"value": ""
|
|
},
|
|
{
|
|
"key": "questionId",
|
|
"value": ""
|
|
}
|
|
],
|
|
"auth": {
|
|
"type": "bearer",
|
|
"bearer": [
|
|
{
|
|
"key": "token",
|
|
"value": "{{token}}",
|
|
"type": "string"
|
|
}
|
|
]
|
|
},
|
|
"item": [
|
|
{
|
|
"name": "01 - Builder Component Catalog",
|
|
"request": {
|
|
"method": "GET",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/component-catalog",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"component-catalog"
|
|
]
|
|
},
|
|
"description": "Returns supported stimulus and response component kinds for dynamic type definitions."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "02 - Validate Dynamic Type Definition",
|
|
"request": {
|
|
"method": "POST",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"stimulus_component_kinds\": [\"INSTRUCTION\", \"TEXT_PASSAGE\"],\n \"response_component_kinds\": [\"MULTIPLE_CHOICE\"]\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/validate-question-type-definition",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"validate-question-type-definition"
|
|
]
|
|
},
|
|
"description": "Validates a candidate dynamic question-type definition before saving."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "03 - Create Question Type Definition (MCQ Dynamic)",
|
|
"request": {
|
|
"method": "POST",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"key\": \"mcq_dynamic_vocab\",\n \"display_name\": \"MCQ Dynamic Vocabulary\",\n \"description\": \"Dynamic multiple-choice template for vocabulary checks.\",\n \"stimulus_component_kinds\": [\"INSTRUCTION\", \"TEXT_PASSAGE\"],\n \"response_component_kinds\": [\"MULTIPLE_CHOICE\"],\n \"status\": \"ACTIVE\"\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/type-definitions",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"type-definitions"
|
|
]
|
|
},
|
|
"description": "Creates a reusable dynamic question-type definition."
|
|
},
|
|
"event": [
|
|
{
|
|
"listen": "test",
|
|
"script": {
|
|
"exec": [
|
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
|
"var json = pm.response.json();",
|
|
"if (json && json.data && json.data.id) {",
|
|
" pm.collectionVariables.set('questionTypeDefinitionId', json.data.id);",
|
|
"}"
|
|
],
|
|
"type": "text/javascript"
|
|
}
|
|
}
|
|
],
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "04 - List Question Type Definitions (Include System)",
|
|
"request": {
|
|
"method": "GET",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/type-definitions?include_system=true&status=ACTIVE",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"type-definitions"
|
|
],
|
|
"query": [
|
|
{
|
|
"key": "include_system",
|
|
"value": "true"
|
|
},
|
|
{
|
|
"key": "status",
|
|
"value": "ACTIVE"
|
|
}
|
|
]
|
|
},
|
|
"description": "Lists reusable dynamic definitions (system + custom)."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "05 - Get Question Type Definition By ID",
|
|
"request": {
|
|
"method": "GET",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/type-definitions/{{questionTypeDefinitionId}}",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"type-definitions",
|
|
"{{questionTypeDefinitionId}}"
|
|
]
|
|
},
|
|
"description": "Fetches one dynamic type-definition by ID."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "06 - Update Question Type Definition",
|
|
"request": {
|
|
"method": "PUT",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"display_name\": \"MCQ Dynamic Vocabulary (Updated)\",\n \"description\": \"Updated dynamic MCQ template.\",\n \"stimulus_component_kinds\": [\"INSTRUCTION\", \"TEXT_PASSAGE\", \"IMAGE\"],\n \"response_component_kinds\": [\"MULTIPLE_CHOICE\", \"ANSWER_TIMER\"],\n \"status\": \"ACTIVE\"\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/type-definitions/{{questionTypeDefinitionId}}",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"type-definitions",
|
|
"{{questionTypeDefinitionId}}"
|
|
]
|
|
},
|
|
"description": "Updates dynamic definition (except key/system flag)."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "07 - Create Question Using question_type_definition_id",
|
|
"request": {
|
|
"method": "POST",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"question_text\": \"Choose the correct synonym for 'rapid'.\",\n \"question_type_definition_id\": {{questionTypeDefinitionId}},\n \"difficulty_level\": \"EASY\",\n \"points\": 1,\n \"status\": \"PUBLISHED\",\n \"options\": [\n { \"option_text\": \"Slow\", \"option_order\": 1, \"is_correct\": false },\n { \"option_text\": \"Quick\", \"option_order\": 2, \"is_correct\": true },\n { \"option_text\": \"Heavy\", \"option_order\": 3, \"is_correct\": false },\n { \"option_text\": \"Late\", \"option_order\": 4, \"is_correct\": false }\n ]\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions"
|
|
]
|
|
},
|
|
"description": "Creates a question by binding to a dynamic definition. Backend infers runtime question_type from the definition."
|
|
},
|
|
"event": [
|
|
{
|
|
"listen": "test",
|
|
"script": {
|
|
"exec": [
|
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
|
"var json = pm.response.json();",
|
|
"if (json && json.data && json.data.id) {",
|
|
" pm.collectionVariables.set('questionId', json.data.id);",
|
|
"}"
|
|
],
|
|
"type": "text/javascript"
|
|
}
|
|
}
|
|
],
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "08 - Create Question (Explicit question_type + Definition)",
|
|
"request": {
|
|
"method": "POST",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"question_text\": \"Pick the antonym of 'expand'.\",\n \"question_type\": \"MCQ\",\n \"question_type_definition_id\": {{questionTypeDefinitionId}},\n \"difficulty_level\": \"MEDIUM\",\n \"points\": 2,\n \"options\": [\n { \"option_text\": \"Increase\", \"option_order\": 1, \"is_correct\": false },\n { \"option_text\": \"Contract\", \"option_order\": 2, \"is_correct\": true },\n { \"option_text\": \"Stretch\", \"option_order\": 3, \"is_correct\": false },\n { \"option_text\": \"Grow\", \"option_order\": 4, \"is_correct\": false }\n ]\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions"
|
|
]
|
|
},
|
|
"description": "Valid combination: explicit question_type must match the type inferred from the selected definition."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "09 - Update Question (Switch/Attach Definition)",
|
|
"request": {
|
|
"method": "PUT",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"question_type_definition_id\": {{questionTypeDefinitionId}},\n \"question_type\": \"MCQ\",\n \"question_text\": \"Choose the best definition of 'meticulous'.\",\n \"options\": [\n { \"option_text\": \"Careless\", \"option_order\": 1, \"is_correct\": false },\n { \"option_text\": \"Very careful and precise\", \"option_order\": 2, \"is_correct\": true },\n { \"option_text\": \"Quickly done\", \"option_order\": 3, \"is_correct\": false }\n ],\n \"status\": \"PUBLISHED\"\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/{{questionId}}",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"{{questionId}}"
|
|
]
|
|
},
|
|
"description": "Updates a question and links (or re-links) it to a dynamic definition."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "10 - Get Question By ID",
|
|
"request": {
|
|
"method": "GET",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/{{questionId}}",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"{{questionId}}"
|
|
]
|
|
},
|
|
"description": "Returns question details (options/short_answers/audio fields as applicable)."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "11 - List Questions",
|
|
"request": {
|
|
"method": "GET",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions?question_type=MCQ&limit=10&offset=0",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions"
|
|
],
|
|
"query": [
|
|
{
|
|
"key": "question_type",
|
|
"value": "MCQ"
|
|
},
|
|
{
|
|
"key": "limit",
|
|
"value": "10"
|
|
},
|
|
{
|
|
"key": "offset",
|
|
"value": "0"
|
|
}
|
|
]
|
|
},
|
|
"description": "Lists questions filtered by runtime question_type."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "12 - Negative Test: Mismatched Type and Definition",
|
|
"request": {
|
|
"method": "POST",
|
|
"header": [
|
|
{
|
|
"key": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
],
|
|
"body": {
|
|
"mode": "raw",
|
|
"raw": "{\n \"question_text\": \"This should fail.\",\n \"question_type\": \"AUDIO\",\n \"question_type_definition_id\": {{questionTypeDefinitionId}},\n \"options\": [\n { \"option_text\": \"A\", \"option_order\": 1, \"is_correct\": true }\n ]\n}"
|
|
},
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions"
|
|
]
|
|
},
|
|
"description": "Expected 400 because explicit question_type does not match inferred type from definition."
|
|
},
|
|
"response": []
|
|
},
|
|
{
|
|
"name": "13 - Delete Custom Question Type Definition",
|
|
"request": {
|
|
"method": "DELETE",
|
|
"header": [],
|
|
"url": {
|
|
"raw": "{{baseUrl}}{{apiPrefix}}/questions/type-definitions/{{questionTypeDefinitionId}}",
|
|
"host": [
|
|
"{{baseUrl}}"
|
|
],
|
|
"path": [
|
|
"{{apiPrefix}}",
|
|
"questions",
|
|
"type-definitions",
|
|
"{{questionTypeDefinitionId}}"
|
|
]
|
|
},
|
|
"description": "Deletes a custom definition. System definitions cannot be deleted."
|
|
},
|
|
"response": []
|
|
}
|
|
]
|
|
}
|