slick-address-kr 1.0.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,16 +7,21 @@ Korean address search library using official road address API - No popup require
7
7
  [![npm version](https://img.shields.io/npm/v/slick-address-kr.svg)](https://www.npmjs.com/package/slick-address-kr)
8
8
  [![license](https://img.shields.io/npm/l/slick-address-kr.svg)](https://github.com/Devguru-J/slick-address-kr/blob/main/LICENSE)
9
9
 
10
+ > v1에서 올라오는 경우 [docs/MIGRATION-v2.md](./docs/MIGRATION-v2.md)를 먼저 읽으세요.
11
+
10
12
  ## 특징
11
13
 
12
14
  - ✨ **팝업 없는 인라인 UI**: 다음 주소 API처럼 새 창이 열리지 않습니다
13
15
  - 🚀 **가벼운 용량**: 외부 의존성 없이 순수 TypeScript로 작성
14
16
  - 📱 **반응형 디자인**: 모바일부터 데스크톱까지 완벽 지원
15
- - 🎨 **커스터마이징 가능**: CSS로 쉽게 스타일 변경 가능
17
+ - 🎨 **커스터마이징 가능**: CSS 변수와 클래스로 쉽게 스타일 변경 가능
18
+ - 🌗 **다크모드 지원**: `--kaf-*` CSS 변수와 `prefers-color-scheme` 대응
16
19
  - ⚡ **자동완성 모드**: 타이핑하는 즉시 검색 결과 표시
17
20
  - ⌨️ **키보드 네비게이션**: 화살표 키로 결과 선택, 엔터로 적용 - 마우스 없이 빠른 입력!
21
+ - ♿ **스크린리더 지원**: ARIA combobox 패턴 적용
18
22
  - 🔒 **TypeScript 지원**: 완전한 타입 정의 제공
19
- - 🌐 **프레임워크 무관**: Vanilla JS, React, Vue 등 어디서나 사용 가능
23
+ - 🌐 **프레임워크 무관**: Vanilla JS는 물론, React/Vue 전용 어댑터 제공
24
+ - 🔌 **자체 프록시 연동**: `endpoint`/`fetchFn` 옵션으로 API 키를 서버에 숨길 수 있음
20
25
  - 📦 **모든 패키지 매니저 지원**: npm, yarn, pnpm, bun, deno 모두 호환
21
26
 
22
27
  ## 설치
@@ -43,21 +48,30 @@ bun add slick-address-kr
43
48
 
44
49
  ### deno
45
50
  ```typescript
46
- import { KoreanAddressFinder } from "npm:slick-address-kr@1.0.2";
51
+ import { KoreanAddressFinder } from "npm:slick-address-kr@2";
47
52
  ```
48
53
 
54
+ > **TypeScript 사용자 참고:** `moduleResolution: "node"`(node10) 설정은
55
+ > 지원하지 않습니다. `"bundler"`, `"node16"`, `"nodenext"` 중 하나를
56
+ > 쓰세요 — 이 패키지는 `exports` 필드 기반 타입 해석만 제공합니다.
57
+
49
58
  ## 빠른 시작
50
59
 
51
60
  ### 1. 기본 사용 (Vanilla JavaScript)
52
61
 
53
62
  **간단한 방법:**
54
63
 
55
- 1. 프로젝트 폴더의 `examples/index.html` 파일을 참조하세요
56
- 2. 로컬 서버 실행:
64
+ 1. 라이브러리를 빌드합니다 (`examples/`는 `../dist/index.js`를 직접 참조하며,
65
+ `dist/`는 git에 커밋되지 않습니다):
66
+ ```bash
67
+ npm run build
68
+ ```
69
+ 2. 프로젝트 폴더의 `examples/index.html` 파일을 참조하세요
70
+ 3. 로컬 서버 실행:
57
71
  ```bash
58
72
  python -m http.server 8000
59
73
  ```
60
- 3. 브라우저에서 열기:
74
+ 4. 브라우저에서 열기:
61
75
  ```
62
76
  http://localhost:8000/examples/
63
77
  ```
@@ -70,101 +84,107 @@ import { KoreanAddressFinder } from "npm:slick-address-kr@1.0.2";
70
84
  <head>
71
85
  <meta charset="UTF-8">
72
86
  <title>주소 검색</title>
87
+ <link rel="stylesheet" href="node_modules/slick-address-kr/dist/styles.css">
73
88
  </head>
74
89
  <body>
75
90
  <div id="address-search"></div>
76
91
 
77
- <script type="module">
78
- // config.js에서 API 키 로드
79
- import { config } from './config.js';
80
-
81
- // 주소 검색 API 호출 함수
82
- async function searchAddress(keyword) {
83
- const response = await fetch(
84
- `https://business.juso.go.kr/addrlink/addrLinkApi.do?` +
85
- `confmKey=${config.jusoApiKey}&keyword=${keyword}&resultType=json`
86
- );
87
- const data = await response.json();
88
- return data.results.juso;
89
- }
90
-
91
- // 검색 UI 구현...
92
+ <script src="node_modules/slick-address-kr/dist/browser.global.js"></script>
93
+ <script>
94
+ // 전역 이름은 window.KoreanAddressFinder다
95
+ const finder = new KoreanAddressFinder({
96
+ apiKey: 'YOUR_API_KEY',
97
+ autocompleteMode: true,
98
+ onSelect: (address, meta) => {
99
+ console.log(meta.reason, address);
100
+ },
101
+ });
102
+
103
+ finder.init(document.getElementById('address-search'));
92
104
  </script>
93
105
  </body>
94
106
  </html>
95
107
  ```
96
108
 
109
+ ESM 환경(모듈 번들러)에서는 다음처럼 씁니다.
110
+
111
+ ```js
112
+ import { KoreanAddressFinder } from 'slick-address-kr';
113
+ import 'slick-address-kr/styles.css';
114
+
115
+ const finder = new KoreanAddressFinder({
116
+ apiKey: 'YOUR_API_KEY',
117
+ onSelect: (address) => console.log(address),
118
+ });
119
+
120
+ finder.init(document.getElementById('address-search'));
121
+ ```
122
+
123
+ CommonJS로 `require`하는 경우, `require('slick-address-kr')`는 이름공간 객체를
124
+ 돌려주므로 `.default`나 이름이 붙은 export를 꺼내 써야 합니다.
125
+
126
+ ```js
127
+ const { KoreanAddressFinder } = require('slick-address-kr');
128
+ // 또는
129
+ const KoreanAddressFinder = require('slick-address-kr').default;
130
+ ```
131
+
97
132
  ### 2. React에서 사용
98
133
 
134
+ 전용 훅을 쓰는 것을 권장합니다.
135
+
99
136
  ```jsx
100
- import React, { useEffect, useRef } from 'react';
101
- import { KoreanAddressFinder } from 'korean-address-finder';
102
- import 'korean-address-finder/dist/styles.css';
103
-
104
- function AddressInput() {
105
- const containerRef = useRef(null);
106
- const finderRef = useRef(null);
107
-
108
- useEffect(() => {
109
- if (containerRef.current && !finderRef.current) {
110
- finderRef.current = new KoreanAddressFinder({
111
- onSelect: (address) => {
112
- console.log('선택된 주소:', address);
113
- }
114
- });
115
-
116
- finderRef.current.init(containerRef.current);
117
- }
118
-
119
- return () => {
120
- if (finderRef.current) {
121
- finderRef.current.destroy();
122
- }
123
- };
124
- }, []);
125
-
126
- return <div ref={containerRef}></div>;
137
+ import { useKoreanAddress } from 'slick-address-kr/react';
138
+ import 'slick-address-kr/styles.css';
139
+
140
+ function AddressForm() {
141
+ const { containerRef, address } = useKoreanAddress({
142
+ apiKey: import.meta.env.VITE_JUSO_API_KEY,
143
+ autocompleteMode: true,
144
+ });
145
+
146
+ return (
147
+ <>
148
+ <div ref={containerRef} />
149
+ {address && <p>{address.zipCode} {address.roadAddress}</p>}
150
+ </>
151
+ );
127
152
  }
128
153
  ```
129
154
 
155
+ 훅 없이 클래스를 직접 다루고 싶다면 `examples/react-example.jsx`를 참고하세요.
156
+
130
157
  ### 3. Vue에서 사용
131
158
 
132
159
  ```vue
133
- <template>
134
- <div ref="addressContainer"></div>
135
- </template>
136
-
137
- <script>
138
- import { KoreanAddressFinder } from 'korean-address-finder';
139
- import 'korean-address-finder/dist/styles.css';
140
-
141
- export default {
142
- mounted() {
143
- this.finder = new KoreanAddressFinder({
144
- onSelect: (address) => {
145
- console.log('선택된 주소:', address);
146
- }
147
- });
160
+ <script setup>
161
+ import { useKoreanAddress } from 'slick-address-kr/vue';
162
+ import 'slick-address-kr/styles.css';
148
163
 
149
- this.finder.init(this.$refs.addressContainer);
150
- },
151
-
152
- beforeUnmount() {
153
- if (this.finder) {
154
- this.finder.destroy();
155
- }
156
- }
157
- };
164
+ const { containerRef, address } = useKoreanAddress({
165
+ apiKey: import.meta.env.VITE_JUSO_API_KEY,
166
+ autocompleteMode: true,
167
+ });
158
168
  </script>
169
+
170
+ <template>
171
+ <div ref="containerRef"></div>
172
+ <p v-if="address">{{ address.zipCode }} {{ address.roadAddress }}</p>
173
+ </template>
159
174
  ```
160
175
 
176
+ > **참고:** `slick-address-kr/vue`의 컴포저블은 `setup()` 시점의 옵션을
177
+ > 한 번만 캡처합니다. React 훅과 달리 이후 `onSelect` 등을 바꿔도
178
+ > 반영되지 않습니다. 콜백을 동적으로 바꿔야 한다면 반환된 `finder` 인스턴스를
179
+ > 직접 조작하세요.
180
+
161
181
  ## API 문서
162
182
 
163
183
  ### Options
164
184
 
165
185
  ```typescript
166
186
  interface AddressFinderOptions {
167
- /** 행정안전부 API 키 (선택사항) */
187
+ /** 행정안전부 API 키. endpoint를 자체 프록시로 지정한 경우 생략 가능 */
168
188
  apiKey?: string;
169
189
 
170
190
  /** 한 페이지에 표시할 결과 수 (기본값: 10) */
@@ -173,11 +193,11 @@ interface AddressFinderOptions {
173
193
  /** 현재 페이지 번호 (기본값: 1) */
174
194
  currentPage?: number;
175
195
 
176
- /** 검색 결과를 표시할 컨테이너 ID */
196
+ /** 검색 결과를 표시할 컨테이너 ID. init()에 엘리먼트를 직접 넘기면 무시됨 */
177
197
  containerId?: string;
178
198
 
179
- /** 주소 선택 시 콜백 함수 */
180
- onSelect?: (address: AddressResult) => void;
199
+ /** 주소 선택 시, 그리고 상세주소가 바뀔 때마다 호출된다 */
200
+ onSelect?: (address: AddressResult, meta: AddressSelectMeta) => void;
181
201
 
182
202
  /** 상세주소 입력 필드 표시 여부 (기본값: true) */
183
203
  showDetailInput?: boolean;
@@ -187,6 +207,12 @@ interface AddressFinderOptions {
187
207
 
188
208
  /** 자동완성 모드 사용 여부 (기본값: false) */
189
209
  autocompleteMode?: boolean;
210
+
211
+ /** 호출할 주소. 자체 프록시 서버를 쓸 때 지정 */
212
+ endpoint?: string;
213
+
214
+ /** fetch 대체 구현. 인증 헤더 주입이나 테스트에 사용 */
215
+ fetchFn?: typeof fetch;
190
216
  }
191
217
  ```
192
218
 
@@ -220,6 +246,21 @@ interface AddressResult {
220
246
 
221
247
  /** 읍면동명 */
222
248
  bname?: string;
249
+
250
+ /** 상세주소·좌표 API 연동에 필요한 원본 코드 (행정구역코드, 도로명코드 등) */
251
+ codes?: AddressCodes;
252
+ }
253
+ ```
254
+
255
+ ### AddressSelectMeta
256
+
257
+ ```typescript
258
+ interface AddressSelectMeta {
259
+ /**
260
+ * 'select' — 사용자가 검색 결과에서 주소를 고른 시점
261
+ * 'detail-change' — 상세주소 입력값이 바뀐 시점
262
+ */
263
+ reason: 'select' | 'detail-change';
223
264
  }
224
265
  ```
225
266
 
@@ -238,21 +279,58 @@ finder.init(document.getElementById('my-container')); // 직접 엘리먼트 전
238
279
 
239
280
  #### `destroy(): void`
240
281
 
241
- 컴포넌트를 제거하고 이벤트 리스너를 정리합니다.
282
+ 컴포넌트를 제거하고 이벤트 리스너를 정리합니다. 여러 번 호출해도 안전합니다.
242
283
 
243
284
  ```javascript
244
285
  finder.destroy();
245
286
  ```
246
287
 
247
- #### `getSelectedAddress(): Object | null`
288
+ #### `getSelectedAddress(): AddressResult | null`
248
289
 
249
- 현재 선택된 주소 정보를 반환합니다.
290
+ 현재 선택된 주소 정보를 반환합니다. 선택 전에는 `null`입니다.
250
291
 
251
292
  ```javascript
252
293
  const selected = finder.getSelectedAddress();
253
- console.log(selected); // { roadAddress, zipCode, detailAddress }
294
+ console.log(selected); // AddressResult | null
295
+ ```
296
+
297
+ #### `search(): Promise<void>`
298
+
299
+ 검색 입력란의 현재 값으로 주소를 검색합니다. 검색 버튼 클릭이나 Enter와
300
+ 같은 동작을 코드에서 그대로 재현할 때 씁니다. 진행 중이던 이전 검색은
301
+ 자동으로 취소됩니다.
302
+
303
+ ```javascript
304
+ await finder.search();
254
305
  ```
255
306
 
307
+ ### 에러 처리
308
+
309
+ API 호출이 실패하면 `JusoApiError`가 던져집니다 (v1처럼 조용히 빈 결과로
310
+ 처리되지 않습니다). `AddressApiClient`를 직접 쓰는 경우:
311
+
312
+ ```javascript
313
+ import { AddressApiClient, JusoApiError } from 'slick-address-kr';
314
+
315
+ const client = new AddressApiClient({ apiKey: 'YOUR_API_KEY' });
316
+
317
+ try {
318
+ const { results, totalCount } = await client.search('판교역로 235', {
319
+ currentPage: 1,
320
+ countPerPage: 10,
321
+ });
322
+ } catch (error) {
323
+ if (error instanceof JusoApiError) {
324
+ // error.code: 행안부 API 원본 에러 코드
325
+ // error.userMessage: 화면에 바로 보여줄 수 있는 한국어 안내
326
+ console.error(error.code, error.userMessage);
327
+ }
328
+ }
329
+ ```
330
+
331
+ `error.userMessage`는 확인된 코드(승인되지 않은 키·도메인 미등록)에만 상세
332
+ 설명을 붙입니다. 그 외 코드는 API가 준 원본 메시지를 그대로 담습니다.
333
+
256
334
  ## 사용 예제
257
335
 
258
336
  ### 자동완성 모드
@@ -261,6 +339,7 @@ console.log(selected); // { roadAddress, zipCode, detailAddress }
261
339
 
262
340
  ```javascript
263
341
  const finder = new KoreanAddressFinder({
342
+ apiKey: 'YOUR_API_KEY',
264
343
  autocompleteMode: true,
265
344
  onSelect: (address) => {
266
345
  console.log(address);
@@ -270,22 +349,21 @@ const finder = new KoreanAddressFinder({
270
349
  finder.init();
271
350
  ```
272
351
 
273
- ### 키보드 네비게이션 🆕
352
+ ### 키보드 네비게이션
274
353
 
275
354
  마우스 없이 키보드만으로 주소를 빠르게 입력할 수 있습니다!
276
355
 
277
356
  **사용 방법:**
278
- - **⬇️ 화살표 아래**: 다음 검색 결과로 이동
279
- - **⬆️ 화살표 위**: 이전 검색 결과로 이동
280
- - **Enter**: 선택된 주소를 폼에 적용
357
+ - **⬇️ 화살표 아래 / ⬆️ 화살표 위**: 검색 결과 사이를 순환 이동
358
+ - **Enter**: 활성화된 결과를 선택 (없으면 검색 실행)
281
359
  - **ESC**: 검색 결과 닫기
282
360
 
283
361
  ```javascript
284
- // 자동완성 모드에서 키보드 네비게이션이 자동으로 활성화됩니다
362
+ // 검색 결과가 열려 있으면 키보드 네비게이션이 자동으로 활성화됩니다
285
363
  const finder = new KoreanAddressFinder({
286
364
  autocompleteMode: true, // 타이핑 시 자동 검색
287
- onSelect: (address) => {
288
- console.log('선택된 주소:', address);
365
+ onSelect: (address, meta) => {
366
+ console.log('선택된 주소:', address, meta.reason);
289
367
  // 폼에 자동으로 입력됩니다
290
368
  }
291
369
  });
@@ -299,6 +377,7 @@ finder.init();
299
377
 
300
378
  ```javascript
301
379
  const finder = new KoreanAddressFinder({
380
+ apiKey: 'YOUR_API_KEY',
302
381
  showDetailInput: false,
303
382
  onSelect: (address) => {
304
383
  console.log(address);
@@ -308,10 +387,37 @@ const finder = new KoreanAddressFinder({
308
387
  finder.init();
309
388
  ```
310
389
 
311
- ### 커스텀 스타일 적용
390
+ ### 자체 프록시 서버로 승인키 숨기기
391
+
392
+ API 키를 클라이언트 번들에 노출하고 싶지 않다면, 자체 서버가 승인키를
393
+ 붙여 행안부 API를 대신 호출하게 하고 `endpoint`만 지정하세요.
394
+
395
+ ```js
396
+ new KoreanAddressFinder({
397
+ endpoint: 'https://your-server.example/api/address',
398
+ // apiKey는 서버가 붙이므로 전달하지 않습니다
399
+ });
400
+ ```
401
+
402
+ 동작하는 예제 서버는 `examples/backend-proxy/`에 있습니다.
403
+
404
+ ### 테마 커스터마이징
405
+
406
+ 색상은 CSS 변수로 바꿀 수 있습니다.
407
+
408
+ ```css
409
+ .kaf-wrapper {
410
+ --kaf-accent: #ff6b35;
411
+ --kaf-border: #ddd;
412
+ }
413
+ ```
414
+
415
+ 다크모드는 `prefers-color-scheme: dark`를 자동으로 따릅니다. 클래스 단위
416
+ 커스터마이징이 필요하면 `customClass` 옵션을 쓰세요.
312
417
 
313
418
  ```javascript
314
419
  const finder = new KoreanAddressFinder({
420
+ apiKey: 'YOUR_API_KEY',
315
421
  customClass: 'my-custom-class',
316
422
  onSelect: (address) => {
317
423
  console.log(address);
@@ -337,10 +443,12 @@ finder.init();
337
443
 
338
444
  ### 1. API 키 발급
339
445
 
340
- 1. [주소기반산업지원서비스](https://business.juso.go.kr/) 접속
446
+ 1. [주소기반산업지원서비스 검색 API 신청](https://business.juso.go.kr/jst/jstAddressApiApplicationWrite) 접속
341
447
  2. 승인키 신청
342
448
  3. ⚠️ **중요: "검색 API" 선택** (팝업 API가 아님!)
343
- 4. 사용할 도메인 등록 (선택사항)
449
+ 4. **사용할 도메인을 등록하세요.** 발급 시 등록한 도메인에서만 호출이
450
+ 허용됩니다. **localhost 개발에는 도메인에 `localhost`를 넣은 별도의
451
+ 개발용 키가 필요합니다.**
344
452
 
345
453
  ### 2. API 키 안전하게 사용하기
346
454
 
@@ -369,12 +477,12 @@ const finder = new KoreanAddressFinder({
369
477
 
370
478
  ```bash
371
479
  # .env
372
- REACT_APP_JUSO_API_KEY=your_key_here
480
+ VITE_JUSO_API_KEY=your_key_here
373
481
  ```
374
482
 
375
483
  ```javascript
376
484
  const finder = new KoreanAddressFinder({
377
- apiKey: process.env.REACT_APP_JUSO_API_KEY,
485
+ apiKey: import.meta.env.VITE_JUSO_API_KEY,
378
486
  onSelect: (address) => console.log(address)
379
487
  });
380
488
  ```
@@ -386,12 +494,13 @@ API 키를 서버에만 저장하고 클라이언트는 자체 서버를 통해
386
494
  ```javascript
387
495
  // 클라이언트에서는 apiKey 불필요
388
496
  const finder = new KoreanAddressFinder({
389
- // 자체 서버 URL 설정 (api-client.ts 수정 필요)
497
+ endpoint: 'https://your-server.example/api/address',
390
498
  onSelect: (address) => console.log(address)
391
499
  });
392
500
  ```
393
501
 
394
- 자세한 내용은 `API-KEY-GUIDE.md` 및 `examples/backend-proxy/` 참조
502
+ 자세한 내용은 [docs/API-KEY-GUIDE.md](./docs/API-KEY-GUIDE.md) 및
503
+ `examples/backend-proxy/` 참조
395
504
 
396
505
  ## 다음 주소 API와의 비교
397
506
 
@@ -414,13 +523,25 @@ const finder = new KoreanAddressFinder({
414
523
  - iOS Safari (12+)
415
524
  - Android Chrome (최신)
416
525
 
526
+ ## 더 읽어보기
527
+
528
+ - [docs/MIGRATION-v2.md](./docs/MIGRATION-v2.md) — v1 → v2 마이그레이션 가이드
529
+ - [docs/QUICK-START.md](./docs/QUICK-START.md) — 빠른 시작
530
+ - [docs/HOW-TO-USE.md](./docs/HOW-TO-USE.md) — 실제 웹사이트 적용 가이드
531
+ - [docs/API-KEY-GUIDE.md](./docs/API-KEY-GUIDE.md) — API 키 발급·관리 가이드
532
+ - [docs/AUTOCOMPLETE-GUIDE.md](./docs/AUTOCOMPLETE-GUIDE.md) — 자동완성 상세 가이드
533
+ - [docs/TEST-GUIDE.md](./docs/TEST-GUIDE.md) — 테스트 가이드
534
+ - [docs/SELF-HOSTED-DATABASE.md](./docs/SELF-HOSTED-DATABASE.md) — 자체 DB 구축
535
+ - [CHANGELOG.md](./CHANGELOG.md) — 버전별 변경 이력
536
+
417
537
  ## 라이선스
418
538
 
419
539
  MIT License - 자유롭게 사용하세요!
420
540
 
421
541
  ## 기여하기
422
542
 
423
- 이슈와 PR은 언제나 환영합니다!
543
+ 이슈와 PR은 언제나 환영합니다! 자세한 개발 절차는
544
+ [CONTRIBUTING.md](./CONTRIBUTING.md)를 참고하세요.
424
545
 
425
546
  1. Fork the repository
426
547
  2. Create your feature branch (`git checkout -b feature/amazing-feature`)
@@ -430,13 +551,24 @@ MIT License - 자유롭게 사용하세요!
430
551
 
431
552
  ## 문제 해결
432
553
 
554
+ ### "승인되지 않은 KEY 입니다" 오류가 나요
555
+
556
+ 이 라이브러리는 **API 키가 필수**입니다. 키 없이 사용하면 동작하지 않습니다.
557
+
558
+ 1. [행정안전부 도로명주소 OpenAPI](https://business.juso.go.kr/jst/jstAddressApiApplicationWrite)에서 **"검색 API"** 키를 직접 발급받으세요. (팝업 API 아님!)
559
+ 2. 발급받은 키를 `apiKey` 옵션으로 전달하세요:
560
+ ```js
561
+ new KoreanAddressFinder({ apiKey: '발급받은_본인_키', /* ... */ });
562
+ ```
563
+ 3. 행정안전부 **개발용(dev) 키는 발급 후 일정 기간이 지나면 만료**됩니다. 만료 시 새로 발급받으세요.
564
+
433
565
  ### CORS 에러가 발생해요
434
566
 
435
567
  행정안전부 API는 CORS를 지원합니다. 만약 에러가 발생한다면:
436
568
 
437
569
  1. API 키가 올바른지 확인
438
570
  2. ⚠️ **중요: API 발급 시 "검색 API"로 발급받았는지 확인** (팝업 API가 아님!)
439
- 3. 도메인이 승인된 도메인인지 확인
571
+ 3. **키 발급 시 등록한 도메인에서만 호출이 허용됩니다.** 사용할 도메인(예: `localhost`, 실제 서비스 도메인)을 juso.go.kr에 등록했는지 확인하세요. **localhost 개발에는 별도의 개발용 키가 필요합니다.**
440
572
  4. HTTPS 사용 권장
441
573
 
442
574
  ### 검색 결과가 나오지 않아요
@@ -444,7 +576,7 @@ MIT License - 자유롭게 사용하세요!
444
576
  1. 인터넷 연결 확인
445
577
  2. API 키가 올바른지 확인
446
578
  3. ⚠️ **API 발급 시 "검색 API"로 선택했는지 확인**
447
- 4. 콘솔에서 에러 메시지 확인
579
+ 4. 콘솔에서 에러 메시지 확인 (v2부터는 `JusoApiError`가 던져지므로 원인이 명확히 보입니다)
448
580
 
449
581
  ## 지원
450
582