@things-factory/integration-data-go-kr 10.0.0-beta.62
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 +73 -0
- package/ROADMAP.md +271 -0
- package/dist-server/engine/connector/data-go-kr-client.d.ts +27 -0
- package/dist-server/engine/connector/data-go-kr-client.js +115 -0
- package/dist-server/engine/connector/data-go-kr-client.js.map +1 -0
- package/dist-server/engine/connector/data-go-kr-connector.d.ts +35 -0
- package/dist-server/engine/connector/data-go-kr-connector.js +59 -0
- package/dist-server/engine/connector/data-go-kr-connector.js.map +1 -0
- package/dist-server/engine/connector/index.d.ts +1 -0
- package/dist-server/engine/connector/index.js +4 -0
- package/dist-server/engine/connector/index.js.map +1 -0
- package/dist-server/engine/index.d.ts +2 -0
- package/dist-server/engine/index.js +5 -0
- package/dist-server/engine/index.js.map +1 -0
- package/dist-server/engine/spec/building-ledger.d.ts +9 -0
- package/dist-server/engine/spec/building-ledger.js +135 -0
- package/dist-server/engine/spec/building-ledger.js.map +1 -0
- package/dist-server/engine/spec/index.d.ts +16 -0
- package/dist-server/engine/spec/index.js +42 -0
- package/dist-server/engine/spec/index.js.map +1 -0
- package/dist-server/engine/spec/types.d.ts +79 -0
- package/dist-server/engine/spec/types.js +30 -0
- package/dist-server/engine/spec/types.js.map +1 -0
- package/dist-server/engine/task/building-ledger/general.d.ts +41 -0
- package/dist-server/engine/task/building-ledger/general.js +92 -0
- package/dist-server/engine/task/building-ledger/general.js.map +1 -0
- package/dist-server/engine/task/building-ledger/index.d.ts +12 -0
- package/dist-server/engine/task/building-ledger/index.js +15 -0
- package/dist-server/engine/task/building-ledger/index.js.map +1 -0
- package/dist-server/engine/task/call.d.ts +33 -0
- package/dist-server/engine/task/call.js +128 -0
- package/dist-server/engine/task/call.js.map +1 -0
- package/dist-server/engine/task/index.d.ts +19 -0
- package/dist-server/engine/task/index.js +22 -0
- package/dist-server/engine/task/index.js.map +1 -0
- package/dist-server/engine/types.d.ts +63 -0
- package/dist-server/engine/types.js +9 -0
- package/dist-server/engine/types.js.map +1 -0
- package/dist-server/index.d.ts +4 -0
- package/dist-server/index.js +10 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/helps/integration/connector/data-go-kr-connector.md +39 -0
- package/helps/integration/services/building-ledger.md +109 -0
- package/helps/integration/task/building-ledger.md +111 -0
- package/helps/integration/task/data-go-kr-call.md +87 -0
- package/package.json +28 -0
- package/server/engine/connector/data-go-kr-client.ts +133 -0
- package/server/engine/connector/data-go-kr-connector.ts +75 -0
- package/server/engine/connector/index.ts +1 -0
- package/server/engine/index.ts +2 -0
- package/server/engine/spec/building-ledger.ts +140 -0
- package/server/engine/spec/index.ts +41 -0
- package/server/engine/spec/types.ts +84 -0
- package/server/engine/task/building-ledger/general.ts +109 -0
- package/server/engine/task/building-ledger/index.ts +12 -0
- package/server/engine/task/call.ts +157 -0
- package/server/engine/task/index.ts +19 -0
- package/server/engine/types.ts +64 -0
- package/server/index.ts +5 -0
- package/things-factory.config.js +1 -0
- package/translations/en.json +11 -0
- package/translations/ja.json +11 -0
- package/translations/ko.json +11 -0
- package/translations/ms.json +11 -0
- package/translations/zh.json +11 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# data.go.kr Connector
|
|
2
|
+
|
|
3
|
+
대한민국 공공데이터포털 **[data.go.kr](https://www.data.go.kr)** 의 모든 Open API 에 대한 공용 커넥터.
|
|
4
|
+
|
|
5
|
+
- **원천**: 각 부처·공공기관 DB (세움터·대법원·통계청·국세청·교통·에너지 등)
|
|
6
|
+
- **공용 URL 체계**: `https://apis.data.go.kr/<기관코드>/<서비스명>/<오퍼레이션>`
|
|
7
|
+
- **인증**: 발급받은 `ServiceKey` 를 쿼리 파라미터로 전달 (Encoding/Decoding 두 형태 모두 수용)
|
|
8
|
+
- **비용**: 무료 (서비스별 활용신청 후 승인)
|
|
9
|
+
|
|
10
|
+
하나의 ServiceKey 로 등록 앱의 **구독 중인 모든 서비스** 를 호출할 수 있으므로, Connection 은 보통 앱·법인당 1개만 생성한다.
|
|
11
|
+
|
|
12
|
+
## 파라미터
|
|
13
|
+
|
|
14
|
+
| 이름 | 필수 | 설명 |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `serviceKey` | O | data.go.kr 일반 인증키 (Decoding/Encoding 모두 허용). 도메인 시크릿으로 저장 권장 |
|
|
17
|
+
| `origin` | △ | API 오리진 오버라이드 (모의 서버/사설 프록시). 기본 `https://apis.data.go.kr` |
|
|
18
|
+
|
|
19
|
+
> Connection 엔티티의 `endpoint` 필드는 무시됩니다. 오리진 변경은 `origin` 파라미터 사용.
|
|
20
|
+
|
|
21
|
+
## 관련 태스크
|
|
22
|
+
|
|
23
|
+
- [`data-go-kr-call`](../task/data-go-kr-call.md) — 범용 오퍼레이션 호출 태스크
|
|
24
|
+
- [`data-go-kr-building-ledger`](../task/building-ledger.md) — 건축물대장 표제부 조회
|
|
25
|
+
|
|
26
|
+
## ServiceKey 발급 (요약)
|
|
27
|
+
|
|
28
|
+
1. [https://www.data.go.kr](https://www.data.go.kr) 가입
|
|
29
|
+
2. 사용하려는 **서비스 상세 페이지** → 활용신청 (1~3영업일 자동 승인)
|
|
30
|
+
3. 마이페이지 → 개발계정 → **일반 인증키 (Decoding)** 복사 → Connection 의 `serviceKey`
|
|
31
|
+
4. 개발계정 일 한도(기본 10,000건) 초과 시 운영계정 신청
|
|
32
|
+
|
|
33
|
+
## 서비스 카탈로그
|
|
34
|
+
|
|
35
|
+
등록된 서비스 스펙은 코드상 `SpecRegistry.listServices()` 로 확인 가능. 현재 등록된 서비스:
|
|
36
|
+
|
|
37
|
+
- [`1613000/BldRgstService_v2` — 국토교통부_건축물대장정보 서비스 v2](../services/building-ledger.md)
|
|
38
|
+
|
|
39
|
+
추가 예정 서비스는 [ROADMAP](https://github.com/hatiolab/things-factory/blob/main/packages/integration-data-go-kr/ROADMAP.md) 참조.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# 건축물대장정보 서비스 v2 (`1613000/BldRgstService_v2`)
|
|
2
|
+
|
|
3
|
+
> 세움터(EAIS) 원천의 건축물대장 정보 Open API. 표제부·총괄표제부·층별개요·부속지번·전유공용면적·주택가격·소유자현황·기본개요 등 **8개 오퍼레이션** 제공.
|
|
4
|
+
|
|
5
|
+
- **data.go.kr 페이지**: https://www.data.go.kr/data/15044713/openapi.do
|
|
6
|
+
- **원천**: 국토교통부 세움터 DB
|
|
7
|
+
- **비용**: 무료 (활용신청 후 개발 1만건/일)
|
|
8
|
+
|
|
9
|
+
## 공통 파라미터 — PNU 5요소
|
|
10
|
+
|
|
11
|
+
모든 오퍼레이션이 동일한 PNU 구성요소로 조회한다:
|
|
12
|
+
|
|
13
|
+
| 파라미터 | 설명 | 예시 |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `sigunguCd` | 시군구코드 5자리 (법정동코드 앞 5자리) | `11680` |
|
|
16
|
+
| `bjdongCd` | 법정동코드 5자리 (법정동코드 뒤 5자리) | `10300` |
|
|
17
|
+
| `platGbCd` | 대지구분 (`0` 대지 / `1` 산 / `2` 블록, 기본 `0`) | `0` |
|
|
18
|
+
| `bun` | 본번 (4자리 zero-pad) | `0223` |
|
|
19
|
+
| `ji` | 부번 (4자리 zero-pad, 없으면 `0000`) | `0000` |
|
|
20
|
+
|
|
21
|
+
PNU 조회 방법:
|
|
22
|
+
- [행정표준코드관리시스템 (code.go.kr)](https://www.code.go.kr) — 법정동코드
|
|
23
|
+
- [V-World 공간정보 오픈플랫폼](https://www.vworld.kr) — 주소→PNU 변환 API
|
|
24
|
+
- 건축물대장 원본 상단의 "고유번호" 19자리 = `[법정동코드 10][platGbCd 1][bun 4][ji 4]`
|
|
25
|
+
|
|
26
|
+
## 오퍼레이션 카탈로그
|
|
27
|
+
|
|
28
|
+
### `getBrTitleInfo` — 표제부 조회
|
|
29
|
+
|
|
30
|
+
건축물대장 표제부(건물 본문) 조회. 연면적·용적률·지상층수·지하층수·주구조·주용도 등 **건물 개요**. 한 필지에 동이 여러 개이면 복수 레코드.
|
|
31
|
+
|
|
32
|
+
**응답 주요 필드**: `totArea`, `vlRat`, `grndFlrCnt`, `ugrndFlrCnt`, `strctCdNm`, `mainPurpsCdNm`, `useAprDay`, `bldNm`, `dongNm`
|
|
33
|
+
|
|
34
|
+
**주의**: 응답의 `items.item` 이 배열 또는 단일 객체로 올 수 있음. 숫자 필드는 문자열(`"114000.00"`)로 내려옴. 집합건축물은 `regstrKindCd=3`, 일반은 `2`.
|
|
35
|
+
|
|
36
|
+
**예시**
|
|
37
|
+
```
|
|
38
|
+
operationRef: 1613000/BldRgstService_v2.getBrTitleInfo
|
|
39
|
+
params: { sigunguCd: "11680", bjdongCd: "10300", bun: "823" }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
→ PNU 5요소 파라미터 폼이 필요하면 [`data-go-kr-building-ledger`](../task/building-ledger.md) 전용 태스크를 이용.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### `getBrRecapTitleInfo` — 총괄표제부 조회
|
|
47
|
+
|
|
48
|
+
집합건축물(아파트 단지 등) 의 총괄표제부. 단지 전체 연면적·대지면적·동 수·세대수 등.
|
|
49
|
+
|
|
50
|
+
**주의**: 일반건축물대장(단동) 에는 레코드 없음. 집합건축물일 때만 유효.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### `getBrFlrOulnInfo` — 층별개요 조회
|
|
55
|
+
|
|
56
|
+
층별로 주용도·구조·면적. 지하 N층부터 지상 M층까지 각 층의 상세 구성.
|
|
57
|
+
|
|
58
|
+
**주의**: 한 필지에 동이 여러 개이면 각 동의 각 층이 모두 나옴 → 건수 多.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### `getBrExposPubuseAreaInfo` — 전유공용면적 조회
|
|
63
|
+
|
|
64
|
+
집합건축물의 호(세대) 별 전유면적·공용면적. 아파트 세대별 실제 면적 산출.
|
|
65
|
+
|
|
66
|
+
**주의**: 집합건축물일 때만 레코드 존재.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### `getBrAtchJibunInfo` — 부속지번 조회
|
|
71
|
+
|
|
72
|
+
대장에 연결된 부속지번(인접 필지 등) 목록.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### `getBrHsprcInfo` — 주택가격 조회
|
|
77
|
+
|
|
78
|
+
공동주택/단독주택 공시가격 이력. 연도별 개별주택가격·공동주택가격.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### `getBrBasisOulnInfo` — 기본개요 조회
|
|
83
|
+
|
|
84
|
+
대장의 기본개요(대장 구분, 대장 종류, 변동일, 변동원인). 변동 이력 추적.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### `getBrExposInfo` — 전유부 조회
|
|
89
|
+
|
|
90
|
+
집합건축물의 호(세대) 목록과 호별 개요. 전유공용면적보다 상위 요약 수준.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 호출 방법
|
|
95
|
+
|
|
96
|
+
모두 범용 태스크 [`data-go-kr-call`](../task/data-go-kr-call.md) 에 `operationRef` 로 지정해서 호출:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"task": "data-go-kr-call",
|
|
101
|
+
"connection": "data-go-kr",
|
|
102
|
+
"params": {
|
|
103
|
+
"operationRef": "1613000/BldRgstService_v2.getBrTitleInfo",
|
|
104
|
+
"params": { "sigunguCd": "...", "bjdongCd": "...", "bun": "..." }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
표제부를 자주 호출한다면 PNU 5요소 폼이 명시된 전용 태스크 `data-go-kr-building-ledger` 사용.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# data-go-kr-building-ledger
|
|
2
|
+
|
|
3
|
+
국토교통부 건축물대장 **표제부**(`getBrTitleInfo`) 를 조회하는 전용 태스크.
|
|
4
|
+
|
|
5
|
+
순수 **fetch** 만 수행합니다 — 집계·변환·요약 같은 도메인 가공은 소비자 스텝에서 처리하세요.
|
|
6
|
+
|
|
7
|
+
## 입력 파라미터
|
|
8
|
+
|
|
9
|
+
PNU(필지고유번호) 5요소로 조회:
|
|
10
|
+
|
|
11
|
+
| 이름 | 필수 | 설명 | 예시 |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `sigunguCd` | O | 시군구코드 5자리 (법정동코드 앞 5자리) | `11680` |
|
|
14
|
+
| `bjdongCd` | O | 법정동코드 5자리 (법정동코드 뒤 5자리) | `10300` |
|
|
15
|
+
| `platGbCd` | △ | 대지구분 (`0` 대지 / `1` 산 / `2` 블록, 기본 `0`) | `0` |
|
|
16
|
+
| `bun` | O | 본번 (자동 4자리 zero-pad) | `223` |
|
|
17
|
+
| `ji` | △ | 부번 (없으면 `0`, 자동 4자리 zero-pad) | `0` |
|
|
18
|
+
|
|
19
|
+
시나리오 변수 치환 지원 — `{{data.project.sigunguCd}}` 바인딩 가능.
|
|
20
|
+
|
|
21
|
+
## 출력
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
{
|
|
25
|
+
"items": [
|
|
26
|
+
{
|
|
27
|
+
"mgmBldrgstPk": "...",
|
|
28
|
+
"platPlc": "...",
|
|
29
|
+
"bldNm": "...",
|
|
30
|
+
"dongNm": "",
|
|
31
|
+
"totArea": "114000.00", // 연면적 (문자열)
|
|
32
|
+
"vlRat": "250", // 용적률 (문자열)
|
|
33
|
+
"grndFlrCnt": "25", // 지상층수 (문자열)
|
|
34
|
+
"ugrndFlrCnt": "3", // 지하층수 (문자열)
|
|
35
|
+
"strctCdNm": "철근콘크리트구조",
|
|
36
|
+
"mainPurpsCdNm": "공동주택",
|
|
37
|
+
"useAprDay": "20230801"
|
|
38
|
+
// ... 기타 20+ 필드
|
|
39
|
+
}
|
|
40
|
+
/* 다동 필지이면 여러 레코드 */
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 중요 — 모든 숫자는 문자열
|
|
46
|
+
|
|
47
|
+
data.go.kr 공통 특성입니다. 숫자로 쓰려면 **후속 스텝** 에서 변환하세요.
|
|
48
|
+
|
|
49
|
+
### 단동 vs 다동
|
|
50
|
+
|
|
51
|
+
- **단동 필지**: `items.length === 1`. `items[0]` 이 대표값.
|
|
52
|
+
- **다동 필지**: `items` 에 각 동이 한 레코드씩. `dongNm` 으로 식별.
|
|
53
|
+
|
|
54
|
+
## 후속 스텝 예시 — 집계는 여기서
|
|
55
|
+
|
|
56
|
+
### 단건 필드 바인딩 (data-mapper)
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"task": "data-mapper",
|
|
61
|
+
"params": {
|
|
62
|
+
"mapping": {
|
|
63
|
+
"totalFloorArea": "items[0].totArea",
|
|
64
|
+
"floorAreaRatio": "items[0].vlRat",
|
|
65
|
+
"aboveGroundFloors": "items[0].grndFlrCnt",
|
|
66
|
+
"belowGroundFloors": "items[0].ugrndFlrCnt"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 다동 필지 집계 (jsonata)
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"task": "jsonata",
|
|
77
|
+
"params": {
|
|
78
|
+
"expression": "{ 'totalFloorArea': $sum(items.totArea.$number()), 'aboveGroundFloors': $max(items.grndFlrCnt.$number()), 'belowGroundFloors': $max(items.ugrndFlrCnt.$number()), 'floorAreaRatio': items[0].vlRat.$number() }"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 도메인 전용 태스크
|
|
84
|
+
|
|
85
|
+
소비자 도메인에서 반복 사용된다면 전용 태스크로 감싸세요. 예를 들어 dkpi 라면:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
dkpi/server/scenario-task/summarize-building-ledger.ts
|
|
89
|
+
→ input: { items: BrTitleItem[] }
|
|
90
|
+
→ output: { totalFloorArea, floorAreaRatio, ... } // KPI 4속성
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
이렇게 하면 "KPI" 어휘가 소비자 측에만 머물고 통합 모듈은 순수한 데이터 조회 레이어로 유지됩니다.
|
|
94
|
+
|
|
95
|
+
## 트러블슈팅
|
|
96
|
+
|
|
97
|
+
### "no 표제부 records" 에러
|
|
98
|
+
|
|
99
|
+
- **신축 공사 중**: 사용승인 전에는 대장이 없음. 프로젝트 시작 시점 입력 후 사용승인 후 재조회.
|
|
100
|
+
- **PNU 오타**: `sigunguCd`(앞 5자리) / `bjdongCd`(뒤 5자리) 가 뒤바뀌지 않았는지 확인.
|
|
101
|
+
- **지번 구조**: "산 N-M" 지번이면 `platGbCd=1` 필요.
|
|
102
|
+
|
|
103
|
+
### 집합건축물(아파트)
|
|
104
|
+
|
|
105
|
+
`items[0].regstrKindCd === '3'` 이면 집합건축물. 더 정확한 단지 전체 연면적은 `getBrRecapTitleInfo`(총괄표제부) + `getBrExposPubuseAreaInfo`(전유공용면적) 조합이 필요합니다. 이 경우 범용 [`data-go-kr-call`](./data-go-kr-call.md) 로 호출하거나 ROADMAP Phase 4 의 집합건축물 전용 태스크를 기다리세요.
|
|
106
|
+
|
|
107
|
+
## 관련
|
|
108
|
+
|
|
109
|
+
- [`data-go-kr-connector`](../connector/data-go-kr-connector.md) — Connection 설정
|
|
110
|
+
- [`data-go-kr-call`](./data-go-kr-call.md) — 범용 호출 (표제부 외 7개 오퍼레이션)
|
|
111
|
+
- [서비스: 건축물대장 v2](../services/building-ledger.md) — 전체 오퍼레이션 카탈로그
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# data-go-kr-call
|
|
2
|
+
|
|
3
|
+
공공데이터포털 **모든 오퍼레이션** 을 호출하는 범용 태스크. 서비스·오퍼레이션별 전용 태스크를 만들지 않아도 되도록 단일 태스크 + 스펙 레지스트리 구조로 동작.
|
|
4
|
+
|
|
5
|
+
## 입력 파라미터
|
|
6
|
+
|
|
7
|
+
| 이름 | 필수 | 설명 | 예시 |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| `operationRef` | O | `<serviceId>.<operationId>` 형식 | `1613000/BldRgstService_v2.getBrTitleInfo` |
|
|
10
|
+
| `params` | △ | 오퍼레이션 파라미터 객체 | `{ "sigunguCd": "11680", "bjdongCd": "10300", "bun": "223" }` |
|
|
11
|
+
|
|
12
|
+
`operationRef` 가 **등록된 스펙** 을 가리키면:
|
|
13
|
+
- 필수 파라미터 검증 / 기본값 주입 / zero-pad / 길이 검증 / enum 검증이 자동 적용
|
|
14
|
+
- 실패 시 친절한 에러 메시지 (어떤 파라미터가 왜 실패했는지)
|
|
15
|
+
|
|
16
|
+
스펙에 **없는 오퍼레이션** 도 호출 가능 (검증 스킵). 새 서비스가 추가되어 아직 스펙이 없어도 즉시 사용 가능.
|
|
17
|
+
|
|
18
|
+
## 출력
|
|
19
|
+
|
|
20
|
+
원 응답 봉투를 그대로 반환:
|
|
21
|
+
|
|
22
|
+
```jsonc
|
|
23
|
+
{
|
|
24
|
+
"response": {
|
|
25
|
+
"header": { "resultCode": "00", "resultMsg": "NORMAL SERVICE." },
|
|
26
|
+
"body": {
|
|
27
|
+
"items": { "item": [ /* ... */ ] },
|
|
28
|
+
"numOfRows": 100,
|
|
29
|
+
"pageNo": 1,
|
|
30
|
+
"totalCount": 1
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
이후 스텝에서 `data.response.body.items.item` 에 접근하면 레코드. 단건/다건이 `item` 이 객체 혹은 배열로 갈리므로 후속 `data-mapper` 로 정규화 권장.
|
|
37
|
+
|
|
38
|
+
## 사용 예시
|
|
39
|
+
|
|
40
|
+
### 건축물대장 표제부 조회
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"task": "data-go-kr-call",
|
|
45
|
+
"connection": "data-go-kr",
|
|
46
|
+
"params": {
|
|
47
|
+
"operationRef": "1613000/BldRgstService_v2.getBrTitleInfo",
|
|
48
|
+
"params": {
|
|
49
|
+
"sigunguCd": "11680",
|
|
50
|
+
"bjdongCd": "10300",
|
|
51
|
+
"bun": "223"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> `platGbCd` 는 기본 `0`, `ji` 는 기본 `0000` 으로 스펙이 채워줍니다.
|
|
58
|
+
|
|
59
|
+
### 새 서비스 즉시 호출 (스펙 등록 전)
|
|
60
|
+
|
|
61
|
+
예를 들어 부동산실거래가 API 가 아직 스펙 등록되지 않았어도:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"task": "data-go-kr-call",
|
|
66
|
+
"params": {
|
|
67
|
+
"operationRef": "1613000/RTMSOBJSvc.getRTMSDataSvcAptTrade",
|
|
68
|
+
"params": {
|
|
69
|
+
"LAWD_CD": "11680",
|
|
70
|
+
"DEAL_YMD": "202504"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
검증은 없지만 호출은 정상 동작. 정식으로 쓰려면 `server/engine/spec/rtms-trade.ts` 로 스펙을 추가해주세요.
|
|
77
|
+
|
|
78
|
+
## 자주 쓰는 경우는 전용 태스크
|
|
79
|
+
|
|
80
|
+
자주 쓰이는 오퍼레이션은 파라미터 폼이 명시된 전용 태스크로 감싸면 운영 UX 가 좋습니다:
|
|
81
|
+
|
|
82
|
+
- [`data-go-kr-building-ledger`](./building-ledger.md) — 건축물대장 표제부 조회 (PNU 폼 제공)
|
|
83
|
+
|
|
84
|
+
## 관련
|
|
85
|
+
|
|
86
|
+
- [`data-go-kr-connector`](../connector/data-go-kr-connector.md) — Connection 설정
|
|
87
|
+
- [서비스: 건축물대장 v2](../services/building-ledger.md) — 8개 오퍼레이션 카탈로그
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@things-factory/integration-data-go-kr",
|
|
3
|
+
"version": "10.0.0-beta.62",
|
|
4
|
+
"main": "dist-server/index.js",
|
|
5
|
+
"things-factory": true,
|
|
6
|
+
"author": "heartyoh <heartyoh@hatiolab.com>",
|
|
7
|
+
"description": "Korean public data portal (data.go.kr) connector for Things-Factory integration engine. Includes generic invocation task and service-specific helpers (e.g., building ledger / 건축물대장).",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public",
|
|
11
|
+
"@things-factory:registry": "https://registry.npmjs.org"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/hatiolab/things-factory.git",
|
|
16
|
+
"directory": "packages/integration-data-go-kr"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc --p tsconfig.json",
|
|
20
|
+
"build:server": "npm run clean:server && tsc",
|
|
21
|
+
"clean:server": "rm -rf dist-server",
|
|
22
|
+
"clean": "npm run clean:server"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@things-factory/integration-base": "^10.0.0-beta.57"
|
|
26
|
+
},
|
|
27
|
+
"gitHead": "5aaec8a7509b2c486e92fba2fd9d893fa5dc2d20"
|
|
28
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { DataGoKrResponse } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 공공데이터포털(data.go.kr) 공용 HTTP 클라이언트.
|
|
5
|
+
*
|
|
6
|
+
* 모든 data.go.kr Open API 는 아래 공통 규약을 따른다:
|
|
7
|
+
* - URL: `https://apis.data.go.kr/<agency>/<service>/<operation>`
|
|
8
|
+
* - 인증: `serviceKey` 쿼리 파라미터 (Encoding/Decoding 두 형태 모두 수용)
|
|
9
|
+
* - 포맷: `_type=json` 없으면 XML
|
|
10
|
+
* - 에러: `<OpenAPI_ServiceResponse>` XML 또는 `response.header.resultCode !== '00'`
|
|
11
|
+
*
|
|
12
|
+
* 본 클라이언트는 서비스·오퍼레이션에 독립적으로 동작하며, 경로를 파라미터로 받는다.
|
|
13
|
+
* 서비스별 도메인 로직(파라미터 검증, 응답 매핑) 은 task 레이어에서 처리.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const DEFAULT_ORIGIN = 'https://apis.data.go.kr'
|
|
17
|
+
|
|
18
|
+
export interface DataGoKrClientOptions {
|
|
19
|
+
serviceKey: string
|
|
20
|
+
/** 오리진 오버라이드 (모의 서버/사설 프록시 용도). 기본 `https://apis.data.go.kr`. */
|
|
21
|
+
origin?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class DataGoKrClient {
|
|
25
|
+
private readonly serviceKey: string
|
|
26
|
+
private readonly origin: string
|
|
27
|
+
|
|
28
|
+
constructor(options: DataGoKrClientOptions) {
|
|
29
|
+
if (!options.serviceKey) {
|
|
30
|
+
throw new Error('DataGoKrClient requires serviceKey')
|
|
31
|
+
}
|
|
32
|
+
/* Encoding 키(%2B 포함)를 붙여넣어도 Decoding 키처럼 동작하도록 정규화.
|
|
33
|
+
base64 키는 `%` 를 포함하지 않으므로 raw Decoding 키는 영향 없음. */
|
|
34
|
+
this.serviceKey = normalizeServiceKey(options.serviceKey.trim())
|
|
35
|
+
this.origin = (options.origin || DEFAULT_ORIGIN).replace(/\/$/, '')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 범용 GET 호출.
|
|
40
|
+
*
|
|
41
|
+
* @param servicePath `<agency>/<service>/<operation>` (예: `1613000/BldRgstService_v2/getBrTitleInfo`)
|
|
42
|
+
* @param params 쿼리 파라미터 (serviceKey / _type 은 자동 추가)
|
|
43
|
+
*/
|
|
44
|
+
async get<T>(servicePath: string, params: Record<string, any>): Promise<DataGoKrResponse<T>> {
|
|
45
|
+
const path = servicePath.startsWith('/') ? servicePath : `/${servicePath}`
|
|
46
|
+
const url = new URL(`${this.origin}${path}`)
|
|
47
|
+
url.searchParams.set('serviceKey', this.serviceKey)
|
|
48
|
+
url.searchParams.set('_type', 'json')
|
|
49
|
+
for (const [k, v] of Object.entries(params)) {
|
|
50
|
+
if (v === undefined || v === null || v === '') continue
|
|
51
|
+
url.searchParams.set(k, String(v))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const response = await fetch(url.toString(), {
|
|
55
|
+
method: 'GET',
|
|
56
|
+
headers: {
|
|
57
|
+
'User-Agent': '@things-factory/integration-data-go-kr',
|
|
58
|
+
Accept: 'application/json'
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
const raw = await response.text()
|
|
62
|
+
|
|
63
|
+
const nonSensitiveParams = Object.entries(params)
|
|
64
|
+
.filter(([, v]) => v !== undefined && v !== null && v !== '')
|
|
65
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
66
|
+
.join(' ')
|
|
67
|
+
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`data.go.kr ${servicePath} failed (${response.status}): ${raw.slice(0, 300)} — params: ${nonSensitiveParams}`
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let parsed: DataGoKrResponse<T>
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(raw) as DataGoKrResponse<T>
|
|
77
|
+
} catch (err) {
|
|
78
|
+
if (raw.includes('<OpenAPI_ServiceResponse') || raw.includes('<returnReasonCode>')) {
|
|
79
|
+
throw new Error(`data.go.kr ${servicePath}: ${parseOpenApiError(raw)} — params: ${nonSensitiveParams}`)
|
|
80
|
+
}
|
|
81
|
+
throw new Error(
|
|
82
|
+
`data.go.kr ${servicePath}: non-JSON response: ${raw.slice(0, 300)} — params: ${nonSensitiveParams}`
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const header = parsed?.response?.header
|
|
87
|
+
if (!header) {
|
|
88
|
+
throw new Error(`data.go.kr ${servicePath}: response missing header — body: ${raw.slice(0, 300)}`)
|
|
89
|
+
}
|
|
90
|
+
if (header.resultCode !== '00') {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`data.go.kr ${servicePath}: resultCode=${header.resultCode} msg=${header.resultMsg} — params: ${nonSensitiveParams}`
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return parsed
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 단건 또는 복수 items 를 배열로 정규화해서 반환한다.
|
|
101
|
+
*
|
|
102
|
+
* data.go.kr 공통 특성으로, body.items 가 아래 세 가지 형태로 올 수 있다:
|
|
103
|
+
* - `""` (빈 문자열, 결과 없음)
|
|
104
|
+
* - `{ item: { ... } }` (단건)
|
|
105
|
+
* - `{ item: [ ... ] }` (복수)
|
|
106
|
+
*/
|
|
107
|
+
async getItems<T>(servicePath: string, params: Record<string, any>): Promise<T[]> {
|
|
108
|
+
const response = await this.get<T>(servicePath, params)
|
|
109
|
+
const items = response.response?.body?.items
|
|
110
|
+
if (!items) return []
|
|
111
|
+
const arr = (items as any).item
|
|
112
|
+
if (!arr) return []
|
|
113
|
+
return Array.isArray(arr) ? arr : [arr]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Encoding 키(%2B) 를 붙여넣어도 Decoding 키로 정규화. */
|
|
118
|
+
function normalizeServiceKey(key: string): string {
|
|
119
|
+
if (!key.includes('%')) return key
|
|
120
|
+
try {
|
|
121
|
+
return decodeURIComponent(key)
|
|
122
|
+
} catch {
|
|
123
|
+
return key
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** data.go.kr 공용 OpenAPI 에러 XML 에서 원인 추출. */
|
|
128
|
+
function parseOpenApiError(xml: string): string {
|
|
129
|
+
const code = /<returnReasonCode>([^<]+)<\/returnReasonCode>/.exec(xml)?.[1]
|
|
130
|
+
const msg = /<errMsg>([^<]+)<\/errMsg>/.exec(xml)?.[1]
|
|
131
|
+
const auth = /<returnAuthMsg>([^<]+)<\/returnAuthMsg>/.exec(xml)?.[1]
|
|
132
|
+
return `code=${code} msg=${msg} auth=${auth}`
|
|
133
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ConnectionManager, Connector } from '@things-factory/integration-base'
|
|
2
|
+
|
|
3
|
+
import { DataGoKrClient } from './data-go-kr-client'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 공공데이터포털(data.go.kr) Open API 커넥터.
|
|
7
|
+
*
|
|
8
|
+
* 하나의 ServiceKey 로 data.go.kr 산하 **모든 오퍼레이션** 을 호출할 수 있으므로,
|
|
9
|
+
* 사용자는 Connection 을 보통 한 개만 만들고 (앱·법인별로 1개) 여러 태스크에서 재사용한다.
|
|
10
|
+
*
|
|
11
|
+
* Connection 의 `endpoint` 필드는 무시된다. 오리진 오버라이드가 필요하면 `origin`
|
|
12
|
+
* 파라미터 사용 (모의 서버/사설 프록시).
|
|
13
|
+
*/
|
|
14
|
+
export interface DataGoKrConnectionInstance {
|
|
15
|
+
client: DataGoKrClient
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class DataGoKrConnector implements Connector {
|
|
19
|
+
async ready(connectionConfigs) {
|
|
20
|
+
await Promise.all(connectionConfigs.map(this.connect.bind(this)))
|
|
21
|
+
ConnectionManager.logger.info('data-go-kr-connector connections are ready')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async connect(connection) {
|
|
25
|
+
const { params } = connection
|
|
26
|
+
try {
|
|
27
|
+
const client = new DataGoKrClient({
|
|
28
|
+
serviceKey: params.serviceKey,
|
|
29
|
+
origin: params.origin
|
|
30
|
+
})
|
|
31
|
+
const instance: DataGoKrConnectionInstance = { client }
|
|
32
|
+
ConnectionManager.addConnectionInstance(connection, instance)
|
|
33
|
+
ConnectionManager.logger.info(`data-go-kr-connector connection(${connection.name}) is connected`)
|
|
34
|
+
} catch (ex) {
|
|
35
|
+
ConnectionManager.logger.error(`data-go-kr-connector connection(${connection.name}) failed`, ex)
|
|
36
|
+
throw ex
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async disconnect(connection) {
|
|
41
|
+
ConnectionManager.removeConnectionInstance(connection)
|
|
42
|
+
ConnectionManager.logger.info(`data-go-kr-connector connection(${connection.name}) is disconnected`)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get parameterSpec() {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
type: 'secret',
|
|
49
|
+
name: 'serviceKey',
|
|
50
|
+
label: 'label.service-key',
|
|
51
|
+
useDomainAttribute: true
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'string',
|
|
55
|
+
name: 'origin',
|
|
56
|
+
label: 'label.api-origin',
|
|
57
|
+
placeholder: 'https://apis.data.go.kr'
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get taskPrefixes() {
|
|
63
|
+
return ['data-go-kr']
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get help() {
|
|
67
|
+
return 'integration/connector/data-go-kr-connector'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get description() {
|
|
71
|
+
return 'Korean Public Data Portal (data.go.kr) Connector'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ConnectionManager.registerConnector('data-go-kr-connector', new DataGoKrConnector())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './data-go-kr-connector'
|