Files
uniare.sori.studio/docs/api-integration.md

177 lines
3.9 KiB
Markdown

# 옆 프로젝트 API 연동 가이드
UNIARE v4부터 덱 데이터는 **공유 코드 + REST API**로 제공합니다.
URL 쿼리(`?cards=`) 방식은 사용하지 않습니다.
## 공식 엔드포인트
```http
GET https://uniare.sori.studio/api/v1/decks/:shareCode
```
### 응답 예시
```json
{
"v": 1,
"shareCode": "x7Kp9m2Q",
"shareType": "user",
"series": "ua36",
"seriesName": "마크로스",
"name": "블루 aggro",
"totalCards": 50,
"cards": [
{
"number": "UA36BT/MCR-1-052",
"count": 4,
"key": true,
"imgSrc": "/ua36/UA36BT_MCR-1-052.png",
"color": "Blue",
"rarity": "SR",
"trigger": null,
"parallel": false
}
],
"author": {
"id": 1,
"displayName": "닉네임",
"avatarUrl": null
},
"createdAt": "2026-06-19T12:00:00Z",
"updatedAt": "2026-06-19T12:00:00Z",
"viewCount": 42,
"isPublic": true
}
```
## shareCode 얻는 방법
| 방법 | 예시 |
|---|---|
| UNIARE 공유 버튼 | `https://uniare.sori.studio/d/x7Kp9m2Q` |
| URL 파라미터 | `cardList.html?d=x7Kp9m2Q` |
| 코드만 | `x7Kp9m2Q` |
## 클라이언트 라이브러리
프로젝트에 포함된 파일:
```
integrations/uadeck-deck-client.js
```
### 브라우저
```html
<script src="https://uniare.sori.studio/integrations/uadeck-deck-client.js"></script>
<script>
const client = new UaDeckDeckClient({
baseUrl: 'https://uniare.sori.studio/api/v1',
imageBase: 'https://uniare.sori.studio',
});
// 공유 링크에서 덱 로드
const deck = await client.fetchFromUrl('https://uniare.sori.studio/d/x7Kp9m2Q');
deck.cards.forEach((card) => {
console.log(card.number, card.count, card.imageUrl);
});
</script>
```
### Node.js / ESM
```javascript
import { UaDeckDeckClient } from './integrations/uadeck-deck-client.js';
const client = new UaDeckDeckClient({
baseUrl: 'https://uniare.sori.studio/api/v1',
});
const deck = await client.fetchDeck('x7Kp9m2Q');
```
### fetch 직접 사용
```javascript
const res = await fetch('https://uniare.sori.studio/api/v1/decks/x7Kp9m2Q');
const deck = await res.json();
if (!res.ok) throw new Error(deck.error);
```
## 이미지 URL 규칙
API의 `imgSrc`는 상대 경로입니다. 전체 URL:
```
https://uniare.sori.studio/images{imgSrc}
```
예: `imgSrc: "/ua36/UA36BT_MCR-1-052.png"`
→ `https://uniare.sori.studio/images/ua36/UA36BT_MCR-1-052.png`
`UaDeckDeckClient`는 `card.imageUrl`에 자동 변환합니다.
## CORS
다른 도메인에서 브라우저 `fetch`를 쓰려면 UNIARE 서버 `.env`의 `CORS_ORIGINS`에 해당 origin을 추가하세요.
```
CORS_ORIGINS=https://your-app.sori.studio,https://uniare.sori.studio
```
서버 간 호출(Node, Python 등)은 CORS가 필요 없습니다.
## 마이그레이션 (기존 ?cards= 코드)
**Before (폐기):**
```javascript
const params = new URLSearchParams(location.search);
const cards = JSON.parse(decodeURIComponent(params.get('cards')));
```
**After:**
```javascript
const code = UaDeckDeckClient.parseShareCode(location.href)
|| new URLSearchParams(location.search).get('d');
const client = new UaDeckDeckClient({ baseUrl: '/api/v1' });
const deck = await client.fetchDeck(code);
const cards = deck.cards;
```
## 공개 덱 목록
```http
GET /api/v1/decks/presets
```
```json
{
"presets": [
{
"share_code": "a7f3b2c1",
"series": "ua36",
"series_name": "마크로스",
"name": "공식 블루 템플릿",
"view_count": 120
}
]
}
```
엔드포인트 이름은 레거시 호환을 위해 `presets`를 유지하지만, 현재 응답 대상은 관리자가 등록한 프리셋이 아니라 사용자가 공개한 미만료 덱입니다.
상세 조회는 동일하게 `GET /decks/:shareCode`를 사용합니다.
## 에러 코드
| HTTP | 의미 |
|---|---|
| 404 | shareCode 없음 |
| 403 | 비공개 덱 |
| 410 | 만료된 임시 공유 (비회원 30일) |