# OBP API 사용자 가이드

## 개요

OBP (OpenBanking Platform) API는 API Gateway의 메트릭 데이터와 API 정보를 JSON 형식으로 제공하는 REST 기반 API입니다.

**API 기본 URL**: `/monitoring/api/`

**지원 형식**: JSON

## 인증 및 권한

### providerCode 파라미터

OBP API는 모든 요청에서 `providerCode` 파라미터로 권한을 검증합니다.

- **허용 값**: `KJB` (대소문자 무시: `kjb`, `Kjb` 등 모두 가능)
- **검증**: 요청 시 providerCode가 반드시 포함되어야 합니다 (필수 파라미터)
- **검증 실패**: 유효하지 않은 providerCode는 `BizException` 에러 발생

**예시**:
```
GET /api/apis/KJB
GET /api/apis/000008-01/KJB
GET /api/metrics/afterTimeslice/20251202030000/KJB
```

## API 엔드포인트

### 1. API 전체 목록 조회

#### 요청

```http
GET /api/apis/{providerCode}
```

**경로 파라미터**:
- `providerCode` (필수): Provider 코드 (KJB만 허용, 대소문자 무시)

**쿼리 파라미터**:
- `pretty` (선택): `true`면 JSON을 들여쓰기 형식으로 반환

**예시**:
```bash
curl "http://localhost:8080/monitoring/api/apis/KJB"
curl "http://localhost:8080/monitoring/api/apis/kjb?pretty=true"
```

#### 응답

```json
[
  {
    "interfaceId": "UAGFF00001UIE",
    "interfaceName": "고객 조회 API",
    "status": "1",
    "description": "고객 기본정보 조회"
  },
  {
    "interfaceId": "UAGFF00002UIE",
    "interfaceName": "거래 조회 API",
    "status": "1",
    "description": "거래 내역 조회"
  }
]
```

**응답 필드**:
- `interfaceId` (string): 인터페이스 ID
- `interfaceName` (string): 인터페이스 명
- `status` (string): 상태 (1=활성)
- `description` (string): 설명

**HTTP 상태 코드**:
- `200 OK`: 조회 성공
- `400 Bad Request`: 유효하지 않은 providerCode
  ```json
  {
    "errorCode": "BIZ_EXCEPTION",
    "errorMessage": "Invalid providerCode. Expected 'KJB' (case-insensitive), got: INVALID"
  }
  ```
- `500 Internal Server Error`: 서버 오류

---

### 2. API 목록 조회 (기관별)

#### 요청

```http
GET /api/apis/{orgCode}/{providerCode}
```

**경로 파라미터**:
- `orgCode` (필수): 기관코드 (OBP 파트너코드)
- `providerCode` (필수): Provider 코드 (KJB만 허용, 대소문자 무시)

**쿼리 파라미터**:
- `pretty` (선택): `true`면 JSON을 들여쓰기 형식으로 반환

**예시**:
```bash
curl "http://localhost:8080/monitoring/api/apis/000008-01/KJB"
curl "http://localhost:8080/monitoring/api/apis/000008-01/kjb?pretty=true"
```

#### 응답

특정 기관이 사용하는 API 목록 (응답 형식은 엔드포인트 1과 동일)

**주의사항**:
- 기관이 존재하지 않으면 빈 배열(`[]`)이 반환됩니다
- 해당 기관의 활성 앱(appstatus='1')이 사용하는 API만 반환됩니다

**HTTP 상태 코드**:
- `200 OK`: 조회 성공 (데이터 있음 또는 없음)
- `400 Bad Request`: 유효하지 않은 providerCode 또는 orgCode
- `500 Internal Server Error`: 서버 오류

---

### 3. GwMetric 데이터 조회 (시간대 이후)

#### 요청

```http
GET /api/metrics/afterTimeslice/{timeslice}/{providerCode}
```

**경로 파라미터**:
- `timeslice` (필수): 조회 시작 시간대 (형식: `yyyyMMddHHmmss`)
  - 예: `20251202030000` (2025-12-02 03:00:00)
  - 분/초는 자동으로 정각(00:00)으로 처리됩니다
- `providerCode` (필수): Provider 코드 (KJB만 허용, 대소문자 무시)

**쿼리 파라미터**:
- `pretty` (선택): `true`면 JSON을 들여쓰기 형식으로 반환

**예시**:
```bash
curl "http://localhost:8080/monitoring/api/metrics/afterTimeslice/20251202030000/KJB"
curl "http://localhost:8080/monitoring/api/metrics/afterTimeslice/20251202030000/kjb?pretty=true"
```

#### 응답

```json
[
  {
    "timeslice": "2025-12-02 03:00:00",
    "transactionCount": 1250,
    "successCount": 1230,
    "failureCount": 20,
    "averageResponseTime": 145
  },
  {
    "timeslice": "2025-12-02 04:00:00",
    "transactionCount": 1380,
    "successCount": 1360,
    "failureCount": 20,
    "averageResponseTime": 152
  }
]
```

**응답 필드**:
- `timeslice` (string): 시간대 (형식: `yyyy-MM-dd HH:00:00`)
- `transactionCount` (number): 총 거래 건수
- `successCount` (number): 성공 건수
- `failureCount` (number): 실패 건수
- `averageResponseTime` (number): 평균 응답 시간 (ms)

**HTTP 상태 코드**:
- `200 OK`: 조회 성공
- `400 Bad Request`: 유효하지 않은 timeslice 또는 providerCode
  ```json
  {
    "errorCode": "BIZ_EXCEPTION",
    "errorMessage": "Invalid timeslice format. Expected 'yyyyMMddHHmmss', got: 2025-12-02_03:00:00"
  }
  ```
- `500 Internal Server Error`: 서버 오류

---

## 예제 코드

### JavaScript (fetch API)

```javascript
// 1. API 전체 목록 조회
async function getAllApis() {
  try {
    const response = await fetch(
      'http://localhost:8080/monitoring/api/apis/KJB?pretty=true'
    );

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    console.log('All APIs:', data);
    return data;
  } catch (error) {
    console.error('Error fetching APIs:', error);
  }
}

// 2. 기관별 API 목록 조회
async function getApisByPartner(partnerCode) {
  try {
    const response = await fetch(
      `http://localhost:8080/monitoring/api/apis/${partnerCode}/KJB?pretty=true`
    );

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    console.log(`APIs for ${partnerCode}:`, data);
    return data;
  } catch (error) {
    console.error('Error fetching APIs:', error);
  }
}

// 3. GwMetric 데이터 조회
async function getMetricsAfterTimeslice(timeslice) {
  try {
    const response = await fetch(
      `http://localhost:8080/monitoring/api/metrics/afterTimeslice/${timeslice}/KJB?pretty=true`
    );

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    console.log(`Metrics after ${timeslice}:`, data);
    return data;
  } catch (error) {
    console.error('Error fetching metrics:', error);
  }
}

// 사용 예
getAllApis();
getApisByPartner('000008-01');
getMetricsAfterTimeslice('20251202030000');
```

### JavaScript (axios)

```javascript
const axios = require('axios');

const BASE_URL = 'http://localhost:8080/monitoring/api';

// 1. API 전체 목록 조회
async function getAllApis() {
  try {
    const response = await axios.get(`${BASE_URL}/apis/KJB`, {
      params: { pretty: true }
    });
    console.log('All APIs:', response.data);
    return response.data;
  } catch (error) {
    console.error('Error fetching APIs:', error.response?.data || error.message);
  }
}

// 2. 기관별 API 목록 조회
async function getApisByPartner(partnerCode) {
  try {
    const response = await axios.get(`${BASE_URL}/apis/${partnerCode}/KJB`, {
      params: { pretty: true }
    });
    console.log(`APIs for ${partnerCode}:`, response.data);
    return response.data;
  } catch (error) {
    console.error('Error fetching APIs:', error.response?.data || error.message);
  }
}

// 3. GwMetric 데이터 조회
async function getMetricsAfterTimeslice(timeslice) {
  try {
    const response = await axios.get(`${BASE_URL}/metrics/afterTimeslice/${timeslice}/KJB`, {
      params: { pretty: true }
    });
    console.log(`Metrics after ${timeslice}:`, response.data);
    return response.data;
  } catch (error) {
    console.error('Error fetching metrics:', error.response?.data || error.message);
  }
}
```

### Java (RestTemplate)

```java
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Map;

public class ObpApiClient {

    private final RestTemplate restTemplate = new RestTemplate();
    private static final String BASE_URL = "http://localhost:8080/monitoring/api";

    // 1. API 전체 목록 조회
    public List<Map> getAllApis() {
        String url = BASE_URL + "/apis/KJB?pretty=true";
        return restTemplate.getForObject(url, List.class);
    }

    // 2. 기관별 API 목록 조회
    public List<Map> getApisByPartner(String partnerCode) {
        String url = BASE_URL + "/apis/" + partnerCode + "/KJB?pretty=true";
        return restTemplate.getForObject(url, List.class);
    }

    // 3. GwMetric 데이터 조회
    public List<Map> getMetricsAfterTimeslice(String timeslice) {
        String url = BASE_URL + "/metrics/afterTimeslice/" + timeslice + "/KJB?pretty=true";
        return restTemplate.getForObject(url, List.class);
    }

    // 사용 예
    public static void main(String[] args) {
        ObpApiClient client = new ObpApiClient();

        // 1. API 목록 조회
        List<Map> apis = client.getAllApis();
        System.out.println("All APIs: " + apis);

        // 2. 기관별 API 조회
        List<Map> partnerApis = client.getApisByPartner("000008-01");
        System.out.println("Partner APIs: " + partnerApis);

        // 3. 메트릭 조회
        List<Map> metrics = client.getMetricsAfterTimeslice("20251202030000");
        System.out.println("Metrics: " + metrics);
    }
}
```

### cURL

```bash
# 1. API 전체 목록 조회
curl "http://localhost:8080/monitoring/api/apis/KJB?pretty=true"
curl "http://localhost:8080/monitoring/api/apis/kjb"

# 2. 기관별 API 목록 조회
curl "http://localhost:8080/monitoring/api/apis/000008-01/KJB?pretty=true"
curl "http://localhost:8080/monitoring/api/apis/000008-01/kjb"

# 3. GwMetric 데이터 조회
curl "http://localhost:8080/monitoring/api/metrics/afterTimeslice/20251202030000/KJB?pretty=true"
curl "http://localhost:8080/monitoring/api/metrics/afterTimeslice/20251202030000/kjb"
```

---

## 에러 처리

### 에러 응답 형식

```json
{
  "errorCode": "BIZ_EXCEPTION",
  "errorMessage": "Invalid providerCode. Expected 'KJB' (case-insensitive), got: INVALID"
}
```

### 주요 에러 코드

| 에러 코드 | HTTP 상태 | 원인 | 해결 방법 |
|---------|---------|------|---------|
| `BIZ_EXCEPTION` | 400 | 유효하지 않은 providerCode | providerCode를 "KJB" (대소문자 무시)로 설정 |
| `BIZ_EXCEPTION` | 400 | 유효하지 않은 timeslice 형식 | timeslice를 `yyyyMMddHHmmss` 형식으로 변경 |
| `INTERNAL_ERROR` | 500 | 서버 오류 | 시스템 관리자에게 문의 |

---

## 마이그레이션 가이드

### 레거시 엔드포인트에서 마이그레이션

레거시 `/kjb/` 경로 엔드포인트는 앞으로 지원이 중단될 예정입니다. 새로운 `/api/` 경로로 마이그레이션하세요.

#### ObpApiController

**기존 엔드포인트** → **새 엔드포인트**

```
GET /kjb/apis.json
  ↓
GET /api/apis/{providerCode}
```

```
GET /kjb/{orgCode}/apis.json
  ↓
GET /api/apis/{orgCode}/{providerCode}
```

**예시**:

기존:
```bash
curl "http://localhost:8080/monitoring/kjb/apis.json"
curl "http://localhost:8080/monitoring/kjb/000008-01/apis.json"
```

새로운:
```bash
curl "http://localhost:8080/monitoring/api/apis/KJB"
curl "http://localhost:8080/monitoring/api/apis/000008-01/KJB"
```

#### ObpGwMetricController

**기존 엔드포인트** → **새 엔드포인트**

```
GET /kjb/gw-metrics/{datetime}.json
  ↓
GET /api/metrics/afterTimeslice/{timeslice}/{providerCode}
```

```
GET /kjb/gw-metrics/after-timeslice/{datetime}.json
  ↓
GET /api/metrics/afterTimeslice/{timeslice}/{providerCode}
```

**datetime 형식 변환**:

| 기존 형식 | 새 형식 |
|---------|--------|
| `yyyy-MM-dd_HH:mm:ss` | `yyyyMMddHHmmss` |
| `2025-12-02_03:00:00` | `20251202030000` |
| `2026-01-18_15:30:45` | `20260118153045` |

**예시**:

기존:
```bash
curl "http://localhost:8080/monitoring/kjb/gw-metrics/2025-12-02_03:00:00.json"
curl "http://localhost:8080/monitoring/kjb/gw-metrics/after-timeslice/2025-12-02_03:00:00.json"
```

새로운:
```bash
curl "http://localhost:8080/monitoring/api/metrics/afterTimeslice/20251202030000/KJB"
```

---

## FAQ

### Q1: providerCode는 무엇인가요?

**A**: providerCode는 API 접근 권한을 검증하는 필수 파라미터입니다. 현재 OBP API는 "KJB" (광주은행)만 허용합니다.

### Q2: providerCode 대소문자를 혼합해도 되나요?

**A**: 네, 가능합니다. `KJB`, `kjb`, `Kjb`, `kJB` 등 모두 허용됩니다.

### Q3: timeslice 형식은 어떻게 변환하나요?

**A**: `yyyy-MM-dd_HH:mm:ss` → `yyyyMMddHHmmss` 형식으로 변환합니다.
- 예: `2025-12-02_03:30:45` → `20251202033045`
- 분과 초도 포함되어 있으므로 정확하게 입력하세요.

### Q4: timeslice에 분/초를 입력해도 되나요?

**A**: 네, 입력 가능합니다. 하지만 시스템은 자동으로 정각(00분, 00초)으로 처리합니다.
- 입력: `20251202033045` (03:30:45)
- 처리: `2025-12-02 03:00:00`

### Q5: 기관이 없으면 어떻게 되나요?

**A**: 기관이 존재하지 않으면 빈 배열(`[]`)이 반환됩니다. 에러가 발생하지 않습니다.

### Q6: 응답 형식을 변경할 수 있나요?

**A**: 현재 JSON 형식만 지원합니다. 다른 형식이 필요하면 시스템 관리자에게 문의하세요.

### Q7: pretty 파라미터를 사용하지 않으면 어떻게 되나요?

**A**: pretty 파라미터를 생략하면 compact한 형식(들여쓰기 없음)으로 반환됩니다.
- `?pretty=true`: 들여쓰기 적용 (가독성 좋음, 용량 큼)
- 파라미터 없음: compact 형식 (가독성 낮음, 용량 작음)

### Q8: API 응답 시간은 어느 정도인가요?

**A**: 응답 로그에 `elapsed` 정보가 포함됩니다. 로그에서도 확인할 수 있습니다.

### Q9: providerCode를 생략할 수 있나요?

**A**: 아니요, providerCode는 필수 파라미터입니다. 반드시 URL 경로에 포함되어야 합니다.

---

## 최신 변경사항

### v2.0 (2025-01-19)

- **새로운 `/api/*` 경로**: RESTful 규칙 준수
  - `/api/apis/{providerCode}` - 전체 API 목록
  - `/api/apis/{orgCode}/{providerCode}` - 기관별 API 목록
  - `/api/metrics/afterTimeslice/{timeslice}/{providerCode}` - GwMetric 데이터
- **Path 변수 기반**: 모든 providerCode/timeslice를 경로 변수로 변경
- **providerCode 검증**: 모든 엔드포인트에서 필수 검증 (KJB 대소문자 무시)
- **timeslice 형식**: `yyyy-MM-dd_HH:mm:ss` → `yyyyMMddHHmmss`
- **레거시 엔드포인트 유지**: `/kjb/*` 경로는 당분간 지원 (Deprecated)

**마이그레이션 권장**: 가능한 한 빨리 새로운 경로로 업데이트하세요.

---

## 지원

문제가 발생하거나 추가 정보가 필요한 경우:

1. **기술 문의**: API 개발팀 (api-support@example.com)
2. **버그 신고**: GitHub Issues
3. **기능 요청**: 관리자에게 연락

---

**마지막 업데이트**: 2025-01-19
**API 버전**: 2.0
