Department and lecture search
A small server that returns departments and lectures as JSON. A front end only needs these two URLs.
Request parameters
Section titled “Request parameters”The example server’s HTTP requests (all GET), and the library methods it calls. Names follow Python snake_case; Node.js takes a camelCase options object and Java takes positional arguments. No login is needed.
Example server
| URL | Parameter | Required | Meaning |
|---|---|---|---|
/departments |
No parameters | ||
/lectures |
department |
No | Department code |
name |
No | Course name (substring). Requiring one of the two is a rule of this example server |
Library methods
| Method | Parameter | Type | Required | Default | Meaning |
|---|---|---|---|---|---|
departments |
category_code |
string | Yes | Organization category (20 undergraduate) |
|
year |
string | Yes | Year | ||
semester_code |
string | Yes | Semester code (10 first, 20 second, 11 and 21 seasonal) |
||
lectures |
category_code, year, semester_code |
string | Yes | Same as above | |
department_code |
string | No | empty string | Department code | |
course_name |
string | No | empty string | Course name | |
instructor_name |
string | No | empty string | Instructor name. With all three conditions empty you get the whole term |
The example code targets undergraduate ("20"); year and semester ("20" = second semester) are constants at the top of the code. All code values are the school’s own; list them with organization_categories() and terms(...) (Department and term codes).
Response data structure
Section titled “Response data structure”The JSON the example server returns. The top block is the response of GET /departments, the bottom one of GET /lectures?...; values only show the shape. Key names follow the Python example; in the Node.js example course_number is courseNumber. The Java controller returns the library models (Department, Lecture) as they are, so it has more fields, named in camelCase.
[ { "code": "3517", "college": "인공지능융합대학", "name": "AI로봇학과" }, { "code": "3331", "college": "연계전공", "name": "스마트투어리즘매니지먼트소프트웨어" }][ { "course": "알고리즘및실습", "department": "컴퓨터공학과", "schedule": "화13:00-15:00", "credits": "3.0", "course_number": "009954" }]| Field | Meaning |
|---|---|
code |
Department code. Pass it as-is to /lectures?department= |
college / name |
College / department (or major) name |
course / department |
Course name / offering department name |
schedule |
Weekday and time (school text, for example 화13:00-15:00) |
credits |
Credits (string) |
course_number |
Course number. Usable to continue to the curriculum lookup |
For every field the library returns, see Course listings and Department and term codes.
On failure: when the school server fails you get the last cached value or an empty list, without an exception. The example server returns it as an empty array ([]).
Good to know
Section titled “Good to know”- Department code, course name and instructor name of
lecturesare all optional. With all of them empty you get the whole term: a response of several MB (Course listings), so the example server requires a condition. If you need everything, query department by department. - Lecture results include the instructor name (
instructor). The examples return only selected fields; decide which fields to expose when you publish this. - Course-name search matches substrings. Some names return 0 results, so show an empty-result hint.
- A lecture’s
course_numberanddepartment_codelead on to the department curriculum entry (grade, semester, course overview) withcurriculum_courses. Curriculum
Example code
Section titled “Example code”import java.util.List;import kr.suhsaechan.sejongpeia.publicdata.SejongPublicData;import kr.suhsaechan.sejongpeia.publicdata.model.Department;import kr.suhsaechan.sejongpeia.publicdata.model.Lecture;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;
@RestControllerclass LectureSearchController {
private static final String UNDERGRADUATE_CATEGORY = "20"; private static final String YEAR = "2026"; private static final String SEMESTER = "20";
private final SejongPublicData publicData;
LectureSearchController(SejongPublicData publicData) { this.publicData = publicData; }
@GetMapping("/departments") List<Department> departments() { return publicData.departments(UNDERGRADUATE_CATEGORY, YEAR, SEMESTER); }
@GetMapping("/lectures") List<Lecture> lectures(@RequestParam(defaultValue = "") String department, @RequestParam(defaultValue = "") String name) { if (department.isBlank() && name.isBlank()) { // no condition returns the whole term (several MB), so this server requires one return List.of(); } return publicData.lectures(UNDERGRADUATE_CATEGORY, YEAR, SEMESTER, department, name, ""); }}A standard library server.
import jsonfrom http.server import BaseHTTPRequestHandler, HTTPServerfrom urllib.parse import parse_qs, urlparse
from sejongpeia import SejongPublicData
public_data = SejongPublicData() # one per process so the cache is sharedUNDERGRADUATE_CATEGORY = "20" # the school's organization category code (list with organization_categories())YEAR, SEMESTER = "2026", "20" # list terms with terms(UNDERGRADUATE_CATEGORY)
def search_lectures(department_code: str, course_name: str) -> list: lectures = public_data.lectures(UNDERGRADUATE_CATEGORY, YEAR, SEMESTER, department_code=department_code, course_name=course_name) return [ {"course": lecture.name, "department": lecture.department_name, "schedule": lecture.schedule, "credits": lecture.credits, "course_number": lecture.course_number} for lecture in lectures ]
class LectureSearchHandler(BaseHTTPRequestHandler): def do_GET(self): url = urlparse(self.path) if url.path == "/departments": departments = public_data.departments(UNDERGRADUATE_CATEGORY, YEAR, SEMESTER) body = [{"code": department.code, "college": department.college_name, "name": department.major_name or department.unit_name} for department in departments] elif url.path == "/lectures": query = parse_qs(url.query) department_code = query.get("department", [""])[0].strip() course_name = query.get("name", [""])[0].strip() if not department_code and not course_name: # no condition returns the whole term (several MB), so this server requires one self.send_error(400, "department or name is required") return body = search_lectures(department_code, course_name) else: self.send_error(404) return payload = json.dumps(body, ensure_ascii=False).encode("utf-8") self.send_response(200) self.send_header("Content-Type", "application/json; charset=utf-8") self.end_headers() self.wfile.write(payload)
if __name__ == "__main__": HTTPServer(("127.0.0.1", 8000), LectureSearchHandler).serve_forever()import { createServer } from 'node:http';import { SejongPublicData } from 'pro-sejongpeia';
const publicData = new SejongPublicData(); // one per process so the cache is sharedconst UNDERGRADUATE_CATEGORY = '20'; // the school's organization category code (list with organizationCategories())const YEAR = '2026';const SEMESTER = '20'; // list terms with terms(UNDERGRADUATE_CATEGORY)
async function searchLectures(departmentCode, courseName) { const lectures = await publicData.lectures({ categoryCode: UNDERGRADUATE_CATEGORY, year: YEAR, semesterCode: SEMESTER, departmentCode, courseName, }); return lectures.map((lecture) => ({ course: lecture.name, department: lecture.departmentName, schedule: lecture.schedule, credits: lecture.credits, courseNumber: lecture.courseNumber, }));}
createServer(async (request, response) => { const url = new URL(request.url, 'http://localhost'); let body; if (url.pathname === '/departments') { const departments = await publicData.departments({ categoryCode: UNDERGRADUATE_CATEGORY, year: YEAR, semesterCode: SEMESTER }); body = departments.map((department) => ({ code: department.code, college: department.collegeName, name: department.majorName || department.unitName })); } else if (url.pathname === '/lectures') { const departmentCode = (url.searchParams.get('department') ?? '').trim(); const courseName = (url.searchParams.get('name') ?? '').trim(); if (!departmentCode && !courseName) { // no condition returns the whole term (several MB), so this server requires one response.writeHead(400).end('department or name is required'); return; } body = await searchLectures(departmentCode, courseName); } else { response.writeHead(404).end(); return; } response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' }).end(JSON.stringify(body));}).listen(8000, '127.0.0.1');