Skip to main content
POST
/
api
/
exam-results
Exam Results
curl --request POST \
  --url https://api.example.com/api/exam-results \
  --header 'Content-Type: application/json' \
  --data '
{
  "examId": "<string>",
  "totalQuestions": 123,
  "correctAnswers": 123,
  "totalTimeMinutes": 123
}
'
{
  "message": "<string>",
  "examResult": {},
  "examResult.examId": "<string>",
  "examResult.barScore": 123,
  "examResult.percentile": 123,
  "examResult.totalQuestions": 123,
  "examResult.correctAnswers": 123,
  "examResult.incorrectAnswers": 123,
  "examResult.skippedAnswers": 123,
  "examResult.totalTimeMinutes": 123,
  "examResult.averageTimePerQuestion": 123,
  "examResult.strengths": [
    {}
  ],
  "examResult.areasForImprovement": [
    {}
  ],
  "examResult.timestamp": "<string>",
  "studyStreak": 123,
  "totalMarks": 123,
  "performanceInsights": [
    {}
  ],
  "error": "<string>"
}

Overview

This endpoint processes and saves bar exam results. It calculates bar scores, percentiles, and time management metrics, retrieves strengths and areas for improvement from a hardcoded mapping, manages performance insights history, and updates study streaks.

Authentication

Requires a valid user UUID passed as a query parameter.

Request

uuid
string
required
Unique identifier for the user

Body Parameters

examId
string
required
Unique identifier for the exam (used to retrieve hardcoded strengths/improvements)
totalQuestions
number
required
Total number of questions in the exam
correctAnswers
number
required
Number of questions answered correctly (can be 0)
totalTimeMinutes
number
required
Total time spent on the exam in minutes (can be 0)

Response

message
string
Success message
examResult
object
Complete exam result object containing:
examResult.examId
string
The exam identifier
examResult.barScore
number
Calculated bar score (4 marks per correct answer)
examResult.percentile
number
Calculated percentile ranking (0-100)
examResult.totalQuestions
number
Total questions in the exam
examResult.correctAnswers
number
Number of correct answers
examResult.incorrectAnswers
number
Number of incorrect answers
examResult.skippedAnswers
number
Number of skipped questions (currently always 0)
examResult.totalTimeMinutes
number
Total time spent in minutes
examResult.averageTimePerQuestion
number
Average time per question in seconds
examResult.strengths
array
Array of identified strengths from hardcoded mapping
examResult.areasForImprovement
array
Array of areas needing improvement from hardcoded mapping
examResult.timestamp
string
ISO timestamp when the result was saved
studyStreak
number
Updated study streak count
totalMarks
number
Maximum possible marks for the exam (totalQuestions × 4)
performanceInsights
array
Array of up to 7 recent exam performance summaries

Score Calculation

Bar Score

Calculated as 4 marks per correct answer:
const barScore = correctAnswers * 4;
Source: /workspace/source/src/app/api/exam-results/route.ts:68

Percentile

Simple formula based on percentage correct:
const percentile = Math.round((correctAnswers / totalQuestions) * 100);
Source: /workspace/source/src/app/api/exam-results/route.ts:71

Time Management

Average time per question in seconds:
const totalTimeSeconds = totalTimeMinutes * 60;
const averageTimePerQuestion = totalTimeSeconds / totalQuestions;
Source: /workspace/source/src/app/api/exam-results/route.ts:74-75

Performance Summary

const incorrectAnswers = totalQuestions - correctAnswers;
const skippedAnswers = 0; // Currently not tracked
Source: /workspace/source/src/app/api/exam-results/route.ts:78-79

Strengths and Improvements Mapping

The endpoint retrieves exam-specific feedback from a hardcoded mapping:
import { examStrengthsAndImprovements } from "@/lib/examStrengthsAndImprovements";

const strengthsAndImprovements = examStrengthsAndImprovements[examId] || {
  strengths: [],
  areasForImprovement: [],
};
Source: /workspace/source/src/app/api/exam-results/route.ts:3,82-85

Performance Insights Tracking

The endpoint maintains a history of up to 7 recent exams:
  • Update Existing: If examId already exists, updates that entry
  • Add New: Adds new exam to the array
  • Limit Enforcement: Removes oldest entry when array reaches 7 items
Source: /workspace/source/src/app/api/exam-results/route.ts:117-144
const existingExamIndex = performanceInsights.findIndex(
  (exam: any) => exam.examId === examId
);

if (existingExamIndex !== -1) {
  // Update existing
  performanceInsights[existingExamIndex] = { ...updatedData };
} else {
  // Add new, remove oldest if >= 7
  if (performanceInsights.length >= 7) {
    performanceInsights.shift();
  }
  performanceInsights.push({ ...newData });
}

Study Streak Logic

Streak increments only on new study days:
const today = new Date().toISOString().split("T")[0];
const lastStudyDate = userData.lastStudyDate || "";
let studyStreak = userData.studyStreak || 0;

if (lastStudyDate !== today) {
  studyStreak += 1; // Only increment if not already studied today
}
Source: /workspace/source/src/app/api/exam-results/route.ts:104-111

Example Request

curl -X POST 'https://api.lsattraining.com/api/exam-results?uuid=user123' \
  -H 'Content-Type: application/json' \
  -d '{
    "examId": "bar_exam_2024_july",
    "totalQuestions": 50,
    "correctAnswers": 38,
    "totalTimeMinutes": 90
  }'

Example Response

{
  "message": "Exam results saved successfully",
  "examResult": {
    "examId": "bar_exam_2024_july",
    "barScore": 152,
    "percentile": 76,
    "totalQuestions": 50,
    "correctAnswers": 38,
    "incorrectAnswers": 12,
    "skippedAnswers": 0,
    "totalTimeMinutes": 90,
    "averageTimePerQuestion": 108,
    "strengths": [
      "Constitutional Law",
      "Contract Analysis",
      "Legal Writing"
    ],
    "areasForImprovement": [
      "Criminal Procedure",
      "Evidence Rules",
      "Time Management"
    ],
    "timestamp": "2024-03-03T15:45:00.000Z"
  },
  "studyStreak": 12,
  "totalMarks": 200,
  "performanceInsights": [
    {
      "examId": "bar_exam_2024_july",
      "totalQuestions": 50,
      "correctAnswers": 38,
      "totalTimeMinutes": 90,
      "timestamp": "2024-03-03T15:45:00.000Z"
    },
    {
      "examId": "bar_exam_2024_feb",
      "totalQuestions": 50,
      "correctAnswers": 35,
      "totalTimeMinutes": 95,
      "timestamp": "2024-02-15T10:30:00.000Z"
    }
  ]
}

Error Responses

error
string
Error message describing what went wrong

400 Bad Request

{
  "error": "UUID is required"
}
{
  "error": "Invalid JSON format"
}
{
  "error": "Missing required fields"
}

404 Not Found

{
  "error": "User not found"
}

500 Internal Server Error

{
  "error": "Failed to save exam results"
}

Firestore Update

The endpoint updates the following fields in the user document:
await userRef.update({
  examResult,              // Complete exam result object
  studyStreak,            // Updated streak
  lastStudyDate: today,   // Current date (YYYY-MM-DD)
  totalMarks,             // Total possible marks
  performanceInsights,    // Array of recent exams (max 7)
});
Source: /workspace/source/src/app/api/exam-results/route.ts:147-153

Implementation Details

  • Database: Firebase Firestore
  • Hardcoded Feedback: Uses examStrengthsAndImprovements mapping
  • History Limit: Maintains maximum 7 performance insights
  • Streak Logic: Increments only on new study days
  • Score Formula: 4 marks per correct answer
  • Percentile: Based on simple percentage correct
  • UUID Processing: Trims whitespace from UUID

Use Cases

  • Progress Tracking: Monitor improvement over multiple exams
  • Performance Analysis: Identify consistent strengths and weaknesses
  • Time Management: Track pacing and time efficiency
  • Motivation: Maintain study streaks
  • Goal Setting: Use percentile and bar score for target setting
Source: /workspace/source/src/app/api/exam-results/route.ts

Build docs developers (and LLMs) love