datagokr-client
v1.0.0
Published
Typed TypeScript client for Korea's public-data APIs (data.go.kr). Fixes the service-key encoding bug, forces JSON, normalizes single-vs-array items, handles pagination, and throws typed errors.
Maintainers
Readme
datagokr-client
A typed TypeScript client for Korea's public-data APIs (data.go.kr). It fixes the things every developer fights the first time: the service-key encoding bug, XML-by-default, the items.item single-vs-array quirk, pagination, and the two different error conventions.
The problem
data.go.kr hosts ~100,000 government APIs (weather, real-estate prices, transit, air quality, festivals, and more). They share the same plumbing, and that plumbing has sharp edges:
- The portal gives you an "Encoding" key and a "Decoding" key. Most HTTP clients re-encode the encoded one and you get
SERVICE_KEY_IS_NOT_REGISTERED_ERROR. It's a rite-of-passage bug. - Responses default to XML; you have to ask for JSON.
items.itemis a single object when there's one result and an array when there are many, so naive.map()code crashes.- There are two success conventions (
"00"and"0000") depending on the API family. - Pagination, timeouts, and quota errors are all on you.
datagokr-client handles all of that once, for any endpoint you point it at. You bring your own key and choose your own API.
Install
npm install datagokr-clientRequires Node 18+ (uses the built-in fetch). Zero runtime dependencies.
Quick start (any API)
import { DataGoKrClient } from "datagokr-client";
const client = new DataGoKrClient({ serviceKey: process.env.DATA_GO_KR_KEY! });
// Short-term weather forecast (기상청). You pick the path and params.
const { items } = await client.get(
"1360000/VilageFcstInfoService_2.0/getVilageFcst",
{ base_date: "20260528", base_time: "0500", nx: 60, ny: 127 },
);You don't pre-encode the key, force JSON, or unwrap the envelope. items is always a clean array.
Paginate everything
for await (const row of client.paginate("B551011/KorService2/searchFestival2", {
eventStartDate: "20260101",
})) {
console.log(row);
}Typed convenience wrappers
A few popular APIs ship as typed one-liners on top of the generic client. The festival search ships first:
import { DataGoKrClient, searchFestival } from "datagokr-client";
const client = new DataGoKrClient({ serviceKey: process.env.DATA_GO_KR_KEY! });
const festivals = await searchFestival(client, { eventStartDate: "20260101" });
// festivals: KtoFestival[] (typed)How it works
| data.go.kr quirk | What datagokr-client does |
|---|---|
| Encoded vs decoded service key | Normalizes to the decoded form so it's percent-encoded exactly once |
| XML by default | Sends _type=json automatically |
| items.item object-or-array | Always returns an array; empty results return [] |
| Two success codes (00 / 0000) | Treats both as success |
| Cryptic failure codes | Throws a typed DataGoKrError with code, resultMsg, and a plain-language hint |
| Pagination | paginate() async iterator with a maxItems quota guard |
| Slow CDN | 20s default timeout, configurable |
Errors
import { DataGoKrError } from "datagokr-client";
try {
await client.get("...");
} catch (e) {
if (e instanceof DataGoKrError) {
console.error(e.code, e.resultMsg);
if (e.hint) console.error("Fix:", e.hint); // e.g. how to resolve a rejected key
}
}Scope and limits
datagokr-client handles the common OpenAPI envelope, which covers the modern majority of APIs (KorService/TourAPI, 기상청, and most others). Some legacy APIs use a different response shape or ignore _type=json — for those, pass a custom itemsPath, or { json: false } and read result.raw. This library deliberately does not try to type all 100,000 APIs; it gives you a great generic client plus a small, growing set of typed wrappers for the popular ones.
License
MIT
