npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

neis-school-info

v0.1.1

Published

대한민국 학교 기본 정보 조회 (나이스 Open API 기반)

Readme

neis-school-info

나이스 교육정보 개방 포털학교 기본 정보를 조회하는 타입스크립트 라이브러리

[!WARNING] '학교기본정보'는 정기적으로 점검되지 않으므로, 휴원이나 학교 형태 변경처럼 두드러진 변경이 없었다면 잘못되었거나 오래된 정보가 남아있을 수 있다.

개발 동기

[!WARNING] '학교기본정보'는 각 시도교육청의 입력값을 엄격하게 검증하지 않고 교육부 총괄 서버로 연계한다.

'학교기본정보' API 명세는 응답값의 형식을 전혀 명시하지 않는다. 다음은 문제가 되는 필드 중 일부이다.

  • 학교를 식별하는 행정표준코드가 없을 수 있으며[^no-code], 이 경우 값은 공백 문자열(" ")로 채워진다.
  • 반면 팩스번호홈페이지주소가 없는 경우 그 값은 공백 문자열이 아닌 null이다.
  • 도로명우편번호는 5자리 숫자여야 하지만 실제 값은 6자리 문자열이다.
    • "12345 "처럼 뒤에 공백이 붙는 경우
    • " 1234 "처럼 오입력된 경우
    • " "처럼 공백만 채워진 경우
  • 전화번호팩스번호는 정형화되어 있지 않다.
    • ., -, 0, 000-0000-0000처럼 사실상 빈 값인 경우
    • 02-000-0000,0001 또는 02-000-0000/02-000-0001처럼 여러 번호를 담은 경우
  • 홈페이지주소도 정형화되어 있지 않다. (예: 도메인 가운데에 공백이 있거나 BOM 문자가 포함됨)
  • 영문학교명, 도로명주소, 도로명상세주소에는 공백이 2개 이상 연속되거나 NBSP 문자가 섞여 있을 수 있다.

[^no-code]: 개교 예정 학교이거나, 이미 개교했지만 코드가 부여되지 않은 학교

이 라이브러리는 값이 없거나 유효하지 않으면 null로 변환한다.

사용법

pnpm i neis-school-info
import { search } from 'neis-school-info';

const result = await search(
	{
		fields: ['학교명', '행정표준코드'], // (선택) 지정된 필드만 검증 후 반환
		filters: { 학교명: 'OO고등학교' }, // (선택) 검색 조건; 아래 참고
		pageIndex: 0, // (선택) 기본값 0; pIndex = pageIndex + 1
		pageSize: 100, // (선택) 기본값 100
	},
	{
		apiKey: 'NEIS_OPEN_API_KEY',
		fetch: customFetch, // (선택) 커스텀 fetch 전달
	},
);

[!IMPORTANT] 타입스크립트로 표현되지 않는 정규화 규칙은 응답값 섹션을 참고한다 (예: 설립일자 등 날짜는 YYYY-MM-DD 형식).

[!NOTE] 다음 경우 search는 결과 대신 예외를 던진다.

  • 인자가 유효하지 않은 경우 (요청 전)
  • 네트워크 오류로 fetch가 실패한 경우
  • 응답이 2xx가 아니거나 JSON이 아닌 경우

검색 조건 (filters)

나이스 OpenAPI와 동일하게 작동하므로 다음과 같은 특성을 가진다:

  • 다중 필터는 AND로 작동함
  • 빈 문자열("")은 무시됨

단, 신청인자로 영문 대신 한글을 사용하며, 행정표준코드가 없는 학교는 null로 검색할 수 있다.

type Filters = Partial<{
	/* 부분 일치 */
	학교명: string; // 예: `OO` → `OO고등학교`, `OO중학교`, `OO초등학교` 검색됨

	/* 완전 일치 */
	설립명: string; // 예: `공` → `공립` 검색 안 됨
	시도교육청코드: 시도교육청코드; // 권장
	시도명: 시도명 | (string & {}); // 지양
	학교종류명: 학교종류명 | (string & {});
	행정표준코드: string | null;
}>;

[!CAUTION] 시도명은 바뀔 수 있으며, 완전 일치이므로 괄호까지도 맞춰야 한다 (예: 전라남도전남광주통합특별시(광주)). 예전 값을 쓰면 오류 없이 빈 배열만 돌아오므로, 시도교육청코드를 쓰는 편이 낫다. 목록

[!NOTE] 시도교육청코드, 설립명 등 열거형은 패키지에서 직접 가져올 수 있다. 전체 목록은 src/index.ts를 참고한다.

좁히기

아래 예제는 필터링 후 타입도 함께 좁혀진다.

[!CAUTION] result.schools를 필터링한 배열의 길이는 result.meta.pageSize와 다를 수 있다.

행정표준코드가 없는 학교 제외

if (result.ok) {
	const schools = result.schools.filter((school) => school.행정표준코드 !== null);
}

여러 학교 종류명으로 필터링

filters.학교종류명은 나이스 API 제약으로 단일 값만 지원한다.

import { filterBy학교종류명, search } from 'neis-school-info';

const result = await search({ filters: { 시도명: '서울특별시' } }, { apiKey: 'NEIS_OPEN_API_KEY' });

if (result.ok) {
	const schools = filterBy학교종류명(result.schools, ['초등학교', '중학교']);
}

응답값

이 라이브러리는 나이스 API 응답값을 검증하고 변환한다 (예: 도로명우편번호는 공백을 제거한 후 5자리 숫자가 아니면 null로 변환함).

result = {
	ok: true,
	code: 'INFO-000',
	meta: {
		pageIndex: 0,
		pageSize: 100,
		totalCount: 12345,
	},
	schools: [
		{
			시도교육청코드: 'OO',
			시도교육청명: 'OO특별시교육청',
			행정표준코드: '0000000',
			학교명: 'OO고등학교',
			영문학교명: 'OO High School',
			// …
		},
	],
};
// result.schools[number]!
type School = {
	/* 열거형 */
	고등학교구분명: 고등학교구분명 | null;
	고등학교일반전문구분명: 고등학교일반전문구분명 | null;
	남녀공학구분명: 남녀공학구분명;
	설립명: 설립명 | null;
	시도교육청코드: 시도교육청코드;
	입시전후기구분명: 입시전후기구분명;
	주야구분명: 주야구분명;

	/* 열거형 - 검증하지 않음, 목록 외 값은 문자열로 통과 */
	학교종류명: 학교종류명 | (string & {}) | null;

	/* 그 외 */
	개교기념일: string; // `YYYY-MM-DD`
	관할조직명: string;
	도로명상세주소: string | null;
	도로명우편번호: string | null; // 5자리 숫자
	도로명주소: string | null;
	산업체특별학급존재여부: 'Y' | 'N';
	설립일자: string; // `YYYY-MM-DD`
	수정일자: string; // `YYYY-MM-DD`
	시도교육청명: string;
	시도명: string;
	영문학교명: string | null;
	전화번호: string | null; // 8~15자리 숫자
	특수목적고등학교계열명: string | null;
	팩스번호: string | null; // 8~15자리 숫자
	학교명: string;
	행정표준코드: string | null;
	홈페이지주소: string | null; // `http(s)://…`
};

[!NOTE] 실패 코드는 ERROR-<000> 또는 INFO-<000> 형식이다. 코드별 설명은 학교 기본 정보 문서를 참고한다.

// 나이스 API가 보고한 오류
result = { ok: false, code: 'ERROR-290', message: '…' };

// 응답 형식이 예상과 다름
result = { ok: false, code: null };

데이터 활용 시 유의사항

  • 학교종류명은 검증하지 않으므로, 타입에 명시된 값 외에 다른 문자열이 올 수 있다.
  • 학교가 고등학교이면서 고등학교일반전문구분명해당없음 또는 null일 수 있다. #1
  • 고등학교구분명일반고인데도 특수목적고등학교계열명 값이 존재할 수 있다. #4