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/CHANGELOG.md +133 -0
- package/README.ko.md +36 -7
- package/README.md +229 -97
- package/dist/address-finder-DIU0lay6.d.cts +236 -0
- package/dist/address-finder-DIU0lay6.d.ts +236 -0
- package/dist/browser.global.js +65 -0
- package/dist/browser.global.js.map +1 -0
- package/dist/chunk-2OLEGOFJ.js +522 -0
- package/dist/chunk-2OLEGOFJ.js.map +1 -0
- package/dist/index.cjs +554 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +46 -0
- package/dist/index.d.ts +44 -6
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +588 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +26 -0
- package/dist/react/index.d.ts +26 -0
- package/dist/react/index.js +51 -0
- package/dist/react/index.js.map +1 -0
- package/dist/styles.css +79 -34
- package/dist/vue/index.cjs +576 -0
- package/dist/vue/index.cjs.map +1 -0
- package/dist/vue/index.d.cts +23 -0
- package/dist/vue/index.d.ts +23 -0
- package/dist/vue/index.js +40 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +89 -19
- package/API-KEY-GUIDE.md +0 -428
- package/AUTOCOMPLETE-GUIDE.md +0 -399
- package/HOW-TO-USE.md +0 -416
- package/config.example.js +0 -16
- package/dist/address-finder.d.ts +0 -68
- package/dist/address-finder.js +0 -262
- package/dist/api-client.d.ts +0 -25
- package/dist/api-client.js +0 -79
- package/dist/types.d.ts +0 -83
- package/dist/types.js +0 -1
- package/index.html +0 -85
- package/korean-address-finder.js +0 -360
package/README.md
CHANGED
|
@@ -7,16 +7,21 @@ Korean address search library using official road address API - No popup require
|
|
|
7
7
|
[](https://www.npmjs.com/package/slick-address-kr)
|
|
8
8
|
[](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
|
|
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@
|
|
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.
|
|
56
|
-
|
|
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
|
-
|
|
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
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
101
|
-
import
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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():
|
|
288
|
+
#### `getSelectedAddress(): AddressResult | null`
|
|
248
289
|
|
|
249
|
-
현재 선택된 주소 정보를 반환합니다.
|
|
290
|
+
현재 선택된 주소 정보를 반환합니다. 선택 전에는 `null`입니다.
|
|
250
291
|
|
|
251
292
|
```javascript
|
|
252
293
|
const selected = finder.getSelectedAddress();
|
|
253
|
-
console.log(selected); //
|
|
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
|
-
|
|
480
|
+
VITE_JUSO_API_KEY=your_key_here
|
|
373
481
|
```
|
|
374
482
|
|
|
375
483
|
```javascript
|
|
376
484
|
const finder = new KoreanAddressFinder({
|
|
377
|
-
apiKey:
|
|
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
|
-
|
|
497
|
+
endpoint: 'https://your-server.example/api/address',
|
|
390
498
|
onSelect: (address) => console.log(address)
|
|
391
499
|
});
|
|
392
500
|
```
|
|
393
501
|
|
|
394
|
-
자세한 내용은
|
|
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
|
|