메인 콘텐츠로 건너뛰기
공식 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 키접근 권한용도
NewClientClient Key읽기 전용게임 클라이언트, 공개 조회
NewServerServer 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 리소스

리소스메서드
CampaignsList(), ListAll(), Get(), GetCreators(), GetPackages()
CreatorsGet(), Search()
CouponsValidate()
SponsorsGet()

Server 리소스

리소스메서드
CampaignsList(), ListAll(), Get(), GetCreators()
CreatorsGet(), Search(), GetCoupons()
CouponsValidate(), Redeem(), GetUserHistory(), ListAllUserHistory()
SponsorsCreate(), GetByUser(), Update(), Delete(), GetHistory(), ListAllHistory()
PaymentsCreate(), Get(), ListByUser(), ListAllByUser(), Refund()
WebhooksList(), 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용도
EnvironmentSandboxhttps://sandbox-sdk-api.playcamp.io개발/테스트
EnvironmentLivehttps://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, &notFoundErr):
        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 상태설명
BadRequestError400잘못된 요청
AuthError401인증 실패
ForbiddenError403권한 부족
NotFoundError404리소스를 찾을 수 없음
ConflictError409리소스 충돌 (중복)
ValidationError422서버 측 유효성 검사 실패
RateLimitError429속도 제한 초과
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 저장소를 참조하세요.