공식 Go SDK (github.com/playcamp/playcamp-go-sdk)는 PlayCamp API와 타입 안전한 연동을 제공합니다. 인증, 페이지네이션, 재시도, 에러 처리를 자동으로 처리하며 외부 의존성이 없습니다.
go get github.com/playcamp/playcamp-go-sdk
요구사항: Go >= 1.21
빠른 시작
import playcamp "github.com/playcamp/playcamp-go-sdk"
server, err := playcamp.NewServer("your_server_key:your_secret",
playcamp.WithEnvironment(playcamp.EnvironmentSandbox),
)
if err != nil {
log.Fatal(err)
}
// 후원 등록
sponsor, err := server.Sponsors.Create(ctx, playcamp.CreateSponsorParams{
UserID: "user_12345",
CreatorKey: "ABC12",
})
// 결제 등록
payment, err := server.Payments.Create(ctx, playcamp.CreatePaymentParams{
UserID: "user_12345",
TransactionID: "txn_abc123",
ProductID: "gem_pack_100",
Amount: 9900,
Currency: "KRW",
Platform: playcamp.PaymentPlatformAndroid,
DistributionType: playcamp.String("MOBILE_STORE"),
PurchasedAt: time.Now(),
})
Client vs Server
SDK는 API 키 유형에 따라 두 가지 생성자를 제공합니다:
| 생성자 | API 키 | 접근 권한 | 용도 |
|---|
NewClient | Client Key | 읽기 전용 | 게임 클라이언트, 공개 조회 |
NewServer | Server Key | 읽기/쓰기 | 게임 서버, 모든 작업 |
import playcamp "github.com/playcamp/playcamp-go-sdk"
// 읽기 전용 (Client Key)
client, err := playcamp.NewClient("your_client_key:your_secret")
// 전체 접근 (Server Key)
server, err := playcamp.NewServer("your_server_key:your_secret")
클라이언트 측에서 NewServer를 사용하거나 Server Key를 노출하지 마세요.
Client 리소스
| 리소스 | 메서드 |
|---|
Campaigns | List(), ListAll(), Get(), GetCreators(), GetPackages() |
Creators | Get(), Search() |
Coupons | Validate() |
Sponsors | Get() |
Server 리소스
| 리소스 | 메서드 |
|---|
Campaigns | List(), ListAll(), Get(), GetCreators() |
Creators | Get(), Search(), GetCoupons() |
Coupons | Validate(), Redeem(), GetUserHistory(), ListAllUserHistory() |
Sponsors | Create(), GetByUser(), Update(), Delete(), GetHistory(), ListAllHistory() |
Payments | Create(), Get(), ListByUser(), ListAllByUser(), Refund() |
Webhooks | List(), Create(), Update(), Delete(), GetLogs(), Test() |
server, err := playcamp.NewServer("key:secret",
playcamp.WithEnvironment(playcamp.EnvironmentSandbox), // 기본값: EnvironmentLive
playcamp.WithTimeout(30 * time.Second), // 기본값: 30s
playcamp.WithTestMode(true), // 기본값: false
playcamp.WithMaxRetries(3), // 기본값: 3
playcamp.WithDebug(playcamp.DebugOptions{ // 기본값: 비활성
Enabled: true,
LogRequestBody: true,
LogResponseBody: true,
}),
)
| 환경 | URL | 용도 |
|---|
EnvironmentSandbox | https://sandbox-sdk-api.playcamp.io | 개발/테스트 |
EnvironmentLive | https://sdk-api.playcamp.io | 프로덕션 (기본값) |
커스텀 URL을 직접 지정할 수도 있습니다:
server, err := playcamp.NewServer("key:secret",
playcamp.WithBaseURL("http://localhost:3003"), // environment 설정을 덮어씀
)
포인터 헬퍼
선택적 필드에 사용하는 내장 헬퍼:
playcamp.String("value") // *string
playcamp.Int(10) // *int
playcamp.Bool(true) // *bool
playcamp.Float64(99.99) // *float64
페이지네이션
목록 조회 엔드포인트는 페이지네이션된 결과를 반환합니다:
// 단일 페이지 조회
result, err := server.Campaigns.List(ctx, &playcamp.PaginationOptions{
Page: playcamp.Int(1),
Limit: playcamp.Int(20),
})
// result.Data, result.Pagination, result.HasNextPage
이터레이터를 사용하면 전체 결과를 자동으로 순회합니다:
iterator := server.Campaigns.ListAll(&playcamp.PaginationOptions{
Limit: playcamp.Int(50),
})
for iterator.Next(ctx) {
campaign := iterator.Item()
fmt.Println(campaign.CampaignID)
iterator.Advance()
}
if err := iterator.Err(); err != nil {
log.Fatal(err)
}
에러 처리
SDK는 시나리오별로 타입이 지정된 에러를 반환합니다:
import "errors"
campaign, err := server.Campaigns.Get(ctx, "invalid_id")
if err != nil {
var notFoundErr *playcamp.NotFoundError
var authErr *playcamp.AuthError
var rateLimitErr *playcamp.RateLimitError
var networkErr *playcamp.NetworkError
var apiErr *playcamp.APIError
switch {
case errors.As(err, ¬FoundErr):
fmt.Println("캠페인을 찾을 수 없음")
case errors.As(err, &authErr):
fmt.Println("잘못된 API 키")
case errors.As(err, &rateLimitErr):
fmt.Println("속도 제한:", rateLimitErr.Message)
case errors.As(err, &networkErr):
fmt.Println("네트워크 에러:", networkErr.Message)
case errors.As(err, &apiErr):
fmt.Printf("API 에러 [%d]: %s\n", apiErr.StatusCode, apiErr.Message)
default:
fmt.Println("예기치 않은 에러:", err)
}
}
| 에러 타입 | HTTP 상태 | 설명 |
|---|
BadRequestError | 400 | 잘못된 요청 |
AuthError | 401 | 인증 실패 |
ForbiddenError | 403 | 권한 부족 |
NotFoundError | 404 | 리소스를 찾을 수 없음 |
ConflictError | 409 | 리소스 충돌 (중복) |
ValidationError | 422 | 서버 측 유효성 검사 실패 |
RateLimitError | 429 | 속도 제한 초과 |
NetworkError | — | 네트워크/타임아웃 에러 |
InputValidationError | — | 클라이언트 측 파라미터 검증 |
웹훅 검증
SDK는 수신 웹훅 서명 검증을 위한 webhookutil 패키지를 제공합니다:
import "github.com/playcamp/playcamp-go-sdk/webhookutil"
func handleWebhook(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
result := webhookutil.Verify(webhookutil.VerifyOptions{
Payload: body,
Signature: r.Header.Get("X-Webhook-Signature"),
Secret: "your_webhook_secret",
Tolerance: 300, // 최대 허용 시간 초 (기본값: 300)
})
if !result.Valid {
http.Error(w, result.Error, http.StatusUnauthorized)
return
}
for _, event := range result.Payload.Events {
switch event.Event {
case playcamp.WebhookEventCouponRedeemed:
var data playcamp.CouponRedeemedData
json.Unmarshal(event.Data, &data)
fmt.Printf("쿠폰 사용: %s\n", data.CouponCode)
case playcamp.WebhookEventPaymentCreated:
var data playcamp.PaymentCreatedData
json.Unmarshal(event.Data, &data)
fmt.Printf("결제 등록: %s\n", data.TransactionID)
case playcamp.WebhookEventSponsorCreated:
var data playcamp.SponsorCreatedData
json.Unmarshal(event.Data, &data)
fmt.Printf("후원 등록: %s\n", data.UserID)
}
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
테스트를 위해 로컬에서 서명을 생성할 수 있습니다:
import "github.com/playcamp/playcamp-go-sdk/webhookutil"
payload := []byte(`{"events":[{"event":"coupon.redeemed","timestamp":"2024-01-15T10:30:00Z","data":{"couponCode":"TEST","userId":"user_123","usageId":1,"reward":[]}}]}`)
signature := webhookutil.ConstructSignature(payload, "your_webhook_secret", nil)
웹훅 이벤트 유형과 페이로드에 대한 자세한 내용은 웹훅 이벤트 페이지를 참조하세요.
예제 프로젝트
전체 API 엔드포인트를 포함하는 완전한 예제는 playcamp-go-sdk-example 저장소를 참조하세요.