Skip to content

Latest commit

 

History

History
616 lines (430 loc) · 12 KB

File metadata and controls

616 lines (430 loc) · 12 KB

API Reference

Class Forge exposes a REST API under the /api/v1 prefix. All request and response bodies use JSON.

Health Check

GET /healthz

Returns the server health status.

Response 200 OK

{
  "status": "ok"
}

Classrooms

POST /api/v1/classrooms

Create a new classroom. The organization (Forgejo) or group (GitLab) must already exist on the platform.

Request Body

Field Type Required Description
name string yes Classroom name (1-255 chars)
description string no Classroom description
organization_name string yes Platform organization/group name
public boolean no Whether the classroom is publicly visible (default: false)

Response 201 Created

{
  "id": 1,
  "name": "Introduction to CS",
  "slug": "introduction-to-cs",
  "description": "CS 101",
  "organization_id": 42,
  "public": false,
  "archived": false,
  "created_at": "2026-03-28T10:00:00Z",
  "updated_at": "2026-03-28T10:00:00Z"
}

Errors

Status Code Cause
400 VALIDATION_ERROR Missing or invalid fields
409 RESOURCE_ALREADY_EXISTS Classroom with same slug exists
502 INTEGRATION_PLATFORM_API_ERROR Platform API call failed

GET /api/v1/classrooms

List all classrooms with pagination.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK

{
  "classrooms": [...],
  "total": 15,
  "page": 1,
  "per_page": 20,
  "total_pages": 1
}

GET /api/v1/classrooms/:id

Get a classroom by ID.

Response 200 OK - Classroom object

Errors 404 if not found


PUT /api/v1/classrooms/:id

Update a classroom. Only provided fields are modified.

Request Body

Field Type Required Description
name string no New name
description string no New description
public boolean no New visibility

Response 200 OK - Updated classroom object


DELETE /api/v1/classrooms/:id

Delete a classroom.

Response 204 No Content


POST /api/v1/classrooms/:id/archive

Archive a classroom. Archived classrooms are read-only.

Response 200 OK - Archived classroom object


GET /api/v1/classrooms/:id/stats

Get classroom statistics.

Response 200 OK

{
  "classroom_id": 1,
  "assignment_count": 5,
  "student_count": 30,
  "submission_count": 120
}

Assignments

POST /api/v1/classrooms/:classroomId/assignments

Create a new assignment in a classroom.

Request Body

Field Type Required Description
name string yes Assignment name (1-255 chars)
description string no Assignment description
template_repository string yes Template repo in owner/name format
max_team_size integer no Max team size (default: 1 for individual)
deadline string (RFC3339) no Submission deadline

Response 201 Created

{
  "id": 1,
  "classroom_id": 1,
  "name": "Homework 1",
  "slug": "homework-1",
  "description": "Implement a linked list",
  "template_repository_id": 100,
  "max_team_size": 1,
  "deadline": "2026-04-15T23:59:59Z",
  "created_at": "2026-03-28T10:00:00Z",
  "updated_at": "2026-03-28T10:00:00Z"
}

Errors

Status Code Cause
400 VALIDATION_ERROR Missing or invalid fields
404 RESOURCE_NOT_FOUND Classroom does not exist
409 RESOURCE_ALREADY_EXISTS Assignment with same slug exists in classroom

GET /api/v1/classrooms/:classroomId/assignments

List assignments in a classroom.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK

{
  "assignments": [...],
  "total": 5,
  "page": 1,
  "per_page": 20,
  "total_pages": 1
}

GET /api/v1/assignments/:id

Get an assignment by ID.

Response 200 OK - Assignment object


PUT /api/v1/assignments/:id

Update an assignment. Only provided fields are modified.

Request Body

Field Type Required Description
name string no New name
description string no New description
max_team_size integer no New max team size
deadline string (RFC3339) no New deadline

Response 200 OK - Updated assignment object


DELETE /api/v1/assignments/:id

Delete an assignment.

Response 204 No Content


GET /api/v1/assignments/:id/stats

Get assignment statistics.

Response 200 OK

{
  "assignment_id": 1,
  "submission_count": 25,
  "team_count": 5,
  "accepted_count": 20
}

Roster (Student Management)

POST /api/v1/classrooms/:classroomId/roster

Add a student to a classroom roster.

Request Body

Field Type Required Description
student_id string yes Institutional student identifier
name string yes Student full name
email string yes Student email address

Response 201 Created

{
  "id": 1,
  "classroom_id": 1,
  "student_id": "alice123",
  "name": "Alice Smith",
  "email": "alice@university.edu",
  "platform_username": "",
  "platform_user_id": 0,
  "created_at": "2026-03-28T10:00:00Z",
  "updated_at": "2026-03-28T10:00:00Z"
}

GET /api/v1/classrooms/:classroomId/roster

List students in a classroom roster.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK

{
  "students": [...],
  "total": 30,
  "page": 1,
  "per_page": 20,
  "total_pages": 2
}

PUT /api/v1/classrooms/:classroomId/roster/:studentId/link

Link a roster entry to a platform account. This enables the student to accept assignments and receive repository access.

Request Body

Field Type Required Description
platform_username string yes Username on the Git platform

Response 200 OK - Updated roster entry


DELETE /api/v1/classrooms/:classroomId/roster/:studentId

Remove a student from the roster.

Response 204 No Content


Submissions

POST /api/v1/assignments/:assignmentId/submissions

Accept an assignment for a student. This creates a repository from the template and grants the student access.

Request Body

Field Type Required Description
student_id integer yes Roster entry ID of the student
team_id integer no Team ID (for team assignments)

Response 201 Created

{
  "id": 1,
  "assignment_id": 1,
  "student_id": 1,
  "repository_id": 999,
  "repository_url": "https://forgejo.example.com/org/hw1-alice-smith.git",
  "status": "active",
  "created_at": "2026-03-28T10:05:00Z"
}

Errors

Status Code Cause
400 BUSINESS_DEADLINE_PASSED Assignment deadline has passed
404 RESOURCE_NOT_FOUND Assignment or student not found
409 RESOURCE_ALREADY_EXISTS Student already accepted this assignment

GET /api/v1/submissions/:id

Get a submission by ID.

Response 200 OK - Submission object


GET /api/v1/assignments/:assignmentId/submissions

List submissions for an assignment.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK

{
  "submissions": [...],
  "total": 25,
  "page": 1,
  "per_page": 20,
  "total_pages": 2
}

GET /api/v1/classrooms/:classroomId/submissions

List all submissions across all assignments in a classroom.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK - Same format as above


Teams

POST /api/v1/assignments/:assignmentId/teams

Create a team for a team-based assignment. The creator becomes the team leader.

Request Body

Field Type Required Description
name string yes Team name (1-255 chars)
description string no Team description
leader_student_id integer yes Roster entry ID of the team leader

Response 201 Created

{
  "id": 1,
  "assignment_id": 2,
  "name": "Team Alpha",
  "slug": "team-alpha",
  "description": "",
  "leader_id": 1,
  "member_count": 1,
  "created_at": "2026-03-28T10:00:00Z"
}

Errors

Status Code Cause
400 BUSINESS_OPERATION_NOT_ALLOWED Assignment is individual-only
404 RESOURCE_NOT_FOUND Assignment not found
409 RESOURCE_ALREADY_EXISTS Team with same slug exists

GET /api/v1/teams/:id

Get a team with its member list.

Response 200 OK

{
  "team": {
    "id": 1,
    "assignment_id": 2,
    "name": "Team Alpha",
    "slug": "team-alpha",
    "leader_id": 1,
    "member_count": 3
  },
  "members": [
    {"student_id": 1, "role": "leader", "name": "Alice Smith"},
    {"student_id": 2, "role": "member", "name": "Bob Jones"},
    {"student_id": 3, "role": "member", "name": "Carol Lee"}
  ]
}

POST /api/v1/teams/:id/join

Add a student to a team.

Request Body

Field Type Required Description
student_id integer yes Roster entry ID of the student

Response 200 OK

Errors

Status Code Cause
400 BUSINESS_TEAM_SIZE_EXCEEDED Team is full
409 RESOURCE_ALREADY_EXISTS Student is already a member

POST /api/v1/teams/:id/leave

Remove a student from a team. Team leaders cannot leave; they must delete the team instead.

Request Body

Field Type Required Description
student_id integer yes Roster entry ID of the student

Response 200 OK

Errors

Status Code Cause
400 BUSINESS_OPERATION_NOT_ALLOWED Team leader cannot leave

DELETE /api/v1/teams/:id

Delete a team and remove all members.

Response 204 No Content


GET /api/v1/assignments/:assignmentId/teams

List teams for an assignment.

Query Parameters

Parameter Type Default Description
page integer 1 Page number
per_page integer 20 Items per page (max 100)

Response 200 OK

{
  "teams": [...],
  "total": 8,
  "page": 1,
  "per_page": 20,
  "total_pages": 1
}

Error Responses

All error responses follow a consistent format:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "classroom 42 not found"
  }
}

Error Codes

Code HTTP Status Description
VALIDATION_ERROR 400 Request validation failed
RESOURCE_NOT_FOUND 404 Requested resource does not exist
RESOURCE_ALREADY_EXISTS 409 Resource with same identifier exists
BUSINESS_OPERATION_NOT_ALLOWED 400 Operation not permitted by business rules
BUSINESS_DEADLINE_PASSED 400 Assignment deadline has passed
BUSINESS_TEAM_SIZE_EXCEEDED 400 Team has reached maximum size
BUSINESS_ROSTER_NOT_FOUND 400 Student not in classroom roster
INTEGRATION_PLATFORM_API_ERROR 502 Git platform API call failed
INTEGRATION_PLATFORM_RATE_LIMITED 429 Platform API rate limit exceeded
INTEGRATION_PLATFORM_UNAVAILABLE 503 Platform is temporarily unavailable

Validation Errors

Validation errors include field-level details:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "validation failed",
    "details": [
      {"field": "name", "message": "Name is required"},
      {"field": "email", "message": "Email must be a valid email address"}
    ]
  }
}